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

时间:2016-05-25 16:03:39

标签: ormlite-servicestack

this comment开始,如何进行连接两个或多个表的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);

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

1 个答案:

答案 0 :(得分:7)

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

因此,当使用Select<T>(SqlExpression<T>) API时,OrmLite将始终尝试将结果映射到db.From<DeptEmployee>()中的主要SqlExpression类型,这不是您想要的自定义列所需的内容。选择的不符合DeptEmployee POCO的形状。

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

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

我们的建议,尤其是对于像OrmLite这样的类型化代码,首先是ORM创建一个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();

这将打印出一个不错的:

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

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

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

如果您对了解不同字段的位置感到高兴,可以选择List<object>,它将按照选择的顺序返回所选字段,例如:

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

打印:

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

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

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

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

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

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

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

你可以制作OrmLite的convenient data access APIs,它可以让你在Dictionary<string,string>中选择2列,例如:

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

打印哪些:

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

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

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

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

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

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

打印哪些:

[
    Last 1,
    Last 2,
    Last 3
]

如果您想要获得不同的结果,可以使用HashSet<string>将其返回到:

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

要回到原来的重点,查询的构造方式并不重要(它只控制生成的SQL),OrmLite 只查看返回的结果集映射结果,它尝试映射到目标API ,您已指定希望将结果映射到其中,因此执行自定义SQL:

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

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

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

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