OrmLite 查询 select 2 个连接表中的某些列

OrmLite query to select some of the columns from each of 2 joined tables

开始,我如何执行一个 ServiceStack OrmLite 查询来连接两个或多个表并return从每个表中提取一些列?

以 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);

上面的 return 不是我所期望的包含 FirstName、LastName 和 Name 的匿名类型列表。它仍然 return 是 DeptEmployee 个对象的列表(但只填充了 FirstName 和 LastName)。

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

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

有几种不同的方式来读取自定义模式,它们都适用于同一个查询(因为它独立于您选择如何映射结果):

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

我们的建议,尤其是。对于像 OrmLite 这样的类型化代码优先 ORM,是创建类型化自定义 POCO 和 select,例如:

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

db.Select<Custom>(q).PrintDump();

这将打印出一个漂亮的:

[
    {
        FirstName: First 1,
        LastName: Last 1,
        Name: Dept 1
    },
]

主要好处是您可以在 List<Custom>.

中获得对自定义结果的类型化访问权限

如果您不想创建自定义类型,您可以 Select OrmLite 的 Dynamic Result APIs,例如:

如果您很高兴知道不同字段的位置,您可以 select 一个 List<object> 这将 return selected 字段按照它们的顺序排列selected,例如:

db.Select<List<object>>(q).PrintDump();

打印:

[
    [
        First 1,
        Last 1,
        Dept 1
    ],
]

否则,如果您还想要名称 returned,您可以 select 一个字符串对象字典,例如:

db.Select<Dictionary<string,object>>(q).PrintDump();

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

[
    {
        FirstName: First 1,
        LastName: Last 1,
        Name: Dept 1
    },
]

如果您只是 selecting 2 列,例如:

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

您可以使用 OrmLite 的 convenient data access APIs,它可以让您 select 2 列变成 Dictionary<string,string>,例如:

db.Dictionary<string,string>(q).PrintDump();

打印:

{
    Last 1: Dept 1,
    Last 2: Dept 2,
    Last 3: Dept 3
}

请注意,这与上面的字符串对象字典非常不同,因为它 returns 导致所有行 Dictionary<string,string> 而不是 List<Dictionary<string,object>>,它有一个字典 每行

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

var q = db.From<DeptEmployee>()
    .Join<Department2>()
    .Select(x => x.LastName);

然后您可以 select 在 List<string> 中的单列结果,例如:

db.Column<string>(q).PrintDump();

打印:

[
    Last 1,
    Last 2,
    Last 3
]

如果您想要不同的结果,您可以 return 在 HashSet<string> 中使用:

db.ColumnDistinct<string>(q).PrintDump();

到return到原来的重点,查询是怎么构造的并不重要(它只是控制生成的SQL),OrmLite 只看returned resultset 以映射结果,它会尝试 映射到您指定的目标 API 您想要的结果映射到,所以执行自定义 SQL:

db.Column<string>("SELECT LastName FROM DeptEmployee").PrintDump();

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

db.Column<string>("EXEC GetLastNamesFromDeptEmployees").PrintDump();

如果您使用类型化 SQL 表达式,则映射方式完全相同,即 OrmLite 仅查看它映射到您想要的结果的结果集 returned.