如何使用 C# 和 Dapper 从 SQL 中的联接表返回一个对象(其中包含另一个对象)?

问题描述 投票:0回答:1

我遇到的问题是,我目前正在尝试获取具有多重映射的对象列表。我想要获取对象 A 的列表,其中包含对象 B,并且两者都单独保存在我的数据库中。以下是我的对象和表格。

对象是:

// Object A
public class TestObject
{

    public int objectId { get; set; }
    public string name { get; set; }
    public ObjectDetail detailId { get; set; }
}

// Object B
public class ObjectDetail
{
        public int detailId { get; set; }
        public string owner { get; set; }
        public string description { get; set; }       

}

我的表是 dbo.testobject,其中包含“objectId”(主键 int)、“name”(nvarchar)、“detailId”(int)列;和 dbo.objectdetail ,其中包含“detailId”(主键 int)、“所有者”(nvarchar)、“描述”(nvarchar)列。

首先,我可以毫无问题地向表中插入行、匹配键以及查询 TestObject 的单个对象,能够调出所有详细信息,包括匹配的 ObjectDetail 中的详细信息。

但是,我一直在尝试获取 TestObject 列表。

我最初所做的是下面的代码。

string sql = $"select ob.*, de.* " +
    $"from dbo.testobject ob " +
    $"left join dbo.objectdetail de " +
    $"on ob.detailId = de.detailId ";

using (IDbConnection connection)
{
    var selected = connection.Query<TestObject, ObjectDetail, TestObject>(sql,
        (test, detail) => { test.detailId = detail; return test; },
        splitOn: "detailId");
}

这会返回错误:

System.Data.DataException:“解析第 2 列时出错(detailId=8 - Int32)”

 and an Inner Exception of
InvalidCastException:从“System.Int32”到“SQLDataAccessDemo.ObjectDetail”的转换无效。

所以我猜测可能是因为 dbo.testobject 中的“detailId”列与 TestObject 类中的detailId 的数据类型不匹配。所以然后我回去并修改了下面的代码。

// I first made changes to the classes
// TestObject is now int Id, string name, ObjectDetail detail
// ObjectDetail object is now int Id, string owner, string description

string sql = $"select ob.*, de.* " +
    $"from dbo.testobject ob " +
    $"left join dbo.objectdetail de " +
    $"on ob.detailId = de.Id ";

using (IDbConnection connection)
{
    var selected = connection.Query<TestObject, ObjectDetail, TestObject>(sql,
        (test, detail) => { test.detail = detail; return test; });

}

哪个有效并且不会给出错误。

所以我的问题是,如何使其工作而不必更改我的初始表?

c# sql sql-server dapper
1个回答
0
投票

建议您不要使用后缀

Id
来命名对象属性。因此,您的
TestObject
类应该包含一个新属性:
ObjectDetail
,它保存对象值。

请使用 Pascal 大小写来命名属性,如下 C# 命名约定。

public class TestObject
{
    public int ObjectId { get; set; }
    public string Name { get; set; }
    public int DetailId  { get; set; }
    public ObjectDetail ObjectDetail { get; set; }
}

public class ObjectDetail
{
    public int Id { get; set; }
    public string Owner { get; set; }
    public string Description { get; set; }       
}

在您的 Dapper 查询中,适用于

splitOn
:

string sql = $"select ob.*, de.* " +
    $"from dbo.testobject ob " +
    $"left join dbo.objectdetail de " +
    $"on ob.detailId = de.Id ";

using (IDbConnection connection)
{
    var selected = connection.Query<TestObject, ObjectDetail, TestObject>(sql,
        (test, detail) => 
        { 
            test.ObjectDetail = detail; 
            return test; 
        }, 
        splitOn: "detailId");
}
© www.soinside.com 2019 - 2024. All rights reserved.