OrmLite查询从2个连接表中的每一个中选择一些列

EM0*_*EM0 5 ormlite-servicestack

本评论之后,我如何进行连接两个或多个表的ServiceStack OrmLite查询并从每个表中返回一些列?

以OrmLite Does_only_populate_Select_fields_wildcard单元测试为例,我想做这样的事情:

public class DeptEmployee
{
    [PrimaryKey]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [References(typeof(Department2))]
    public int DepartmentId { get; set; }

    [Reference]
    public Department2 Department { get; set; }
}

public class Department2
{
    [PrimaryKey]
    public int Id { get; set; }
    public string Name { get; set; }
}

var q = db.From<DeptEmployee>()
    .Join<Department2>()
    .Select<DeptEmployee, Department2>((de, d2) => new[] { de.FirstName, de.LastName, d2.Name });
var results = db.Select(q);
Run Code Online (Sandbox Code Playgroud)

上面没有返回包含FirstName,LastName和Name的匿名类型列表,正如我所期望的那样.它仍然返回一个DeptEmployee对象列表(但只填充了FirstName和LastName).

myt*_*thz 7

在OrmLite中需要注意的一件重要事情是查询的构造和执行方式与结果的映射方式无关.无论查询是原始自定义SQL还是类型化SQL表达式都无关紧要,OrmLite仅查看返回的数据集以查看结果应如何映射.

因此,当使用Select<T>(SqlExpression<T>)API时,OrmLite将始终尝试将结果映射到主要的SqlExpression类型,db.From<DeptEmployee>()而不是您想要的,因为您选择的自定义列与DeptEmployeePOCO 的形状不匹配.

有几种不同的方法可以读取自定义模式,这些模式都可以处理相同的查询(因为它与您选择映射结果的方式无关):

var q = db.From<DeptEmployee>()
    .Join<Department2>()
    .Select<DeptEmployee, Department2>(
        (de, d2) => new { de.FirstName, de.LastName, d2.Name });
Run Code Online (Sandbox Code Playgroud)

我们的建议,尤其是 对于像OrmLite这样的类型化代码,首先是创建一个Typed Custom POCO并选择它,例如:

class Custom
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Name { get; set; }
}

db.Select<Custom>(q).PrintDump();
Run Code Online (Sandbox Code Playgroud)

这将打印出一个很好的:

[
    {
        FirstName: First 1,
        LastName: Last 1,
        Name: Dept 1
    },
]
Run Code Online (Sandbox Code Playgroud)

主要好处是您可以获得对自定义结果的类型访问权限List<Custom>.

如果您不想创建自定义类型,可以选择OrmLite的动态结果API,例如:

如果您很高兴知道不同字段的位置,您可以选择一个List<object>将按选择的顺序返回所选字段,例如:

db.Select<List<object>>(q).PrintDump();
Run Code Online (Sandbox Code Playgroud)

打印:

[
    [
        First 1,
        Last 1,
        Dept 1
    ],
]
Run Code Online (Sandbox Code Playgroud)

否则,如果您还想要返回的名称,则可以选择字符串对象字典,例如:

db.Select<Dictionary<string,object>>(q).PrintDump();
Run Code Online (Sandbox Code Playgroud)

其打印结果类似于自定义POCO,但名称和相应的值保存在松散类型的对象字典中:

[
    {
        FirstName: First 1,
        LastName: Last 1,
        Name: Dept 1
    },
]
Run Code Online (Sandbox Code Playgroud)

如果您只选择2列,例如:

var q = db.From<DeptEmployee>()
    .Join<Department2>()
    .Select<DeptEmployee, Department2>(
        (de, d2) => new { de.LastName, d2.Name });
Run Code Online (Sandbox Code Playgroud)

您可以使用OrmLite 方便的数据访问API,它可以让您在a中选择2列Dictionary<string,string>,例如:

db.Dictionary<string,string>(q).PrintDump();
Run Code Online (Sandbox Code Playgroud)

哪个印刷品:

{
    Last 1: Dept 1,
    Last 2: Dept 2,
    Last 3: Dept 3
}
Run Code Online (Sandbox Code Playgroud)

请注意,这与上面的字符串对象字典非常不同,因为它返回Dictionary<string,string> 所有行的结果,而不是每行List<Dictionary<string,object>>的字典.

同样,如果您只选择1个字段,例如:

var q = db.From<DeptEmployee>()
    .Join<Department2>()
    .Select(x => x.LastName);
Run Code Online (Sandbox Code Playgroud)

然后,您可以在a中选择单个结果列List<string>,例如:

db.Column<string>(q).PrintDump();
Run Code Online (Sandbox Code Playgroud)

哪个印刷品:

[
    Last 1,
    Last 2,
    Last 3
]
Run Code Online (Sandbox Code Playgroud)

如果你想要不同的结果,你可以将它们返回到HashSet<string>:

db.ColumnDistinct<string>(q).PrintDump();
Run Code Online (Sandbox Code Playgroud)

要返回到原来的很重要的一点,不要紧查询是如何构造的(这只是控制系统产生的SQL),OrmLite 只着眼于返回的结果集映射的结果,它试图映射到目标API是您已指定希望将结果映射到,因此执行自定义SQL:

db.Column<string>("SELECT LastName FROM DeptEmployee").PrintDump();
Run Code Online (Sandbox Code Playgroud)

或者,如果您执行了存储过程:

db.Column<string>("EXEC GetLastNamesFromDeptEmployees").PrintDump();
Run Code Online (Sandbox Code Playgroud)

如果使用类型化SQL表达式,则映射方式完全相同,即OrmLite仅查看结果集,该结果集将映射到您希望结果返回的结果.