如何创建可重用的实体框架投影表达式?

Posted

技术标签:

【中文标题】如何创建可重用的实体框架投影表达式?【英文标题】:How can I create a reusable Entity Framework projection expression? 【发布时间】:2016-04-18 17:51:59 【问题描述】:

在我的数据库中,有几十列的表:

Table MyEntity: int Id string Name string Email ...dozens of other columns I never use in this project

EF 生成的类具有这些额外列的属性,一个简单的查询获取所有这些额外的列,很浪费。

相反,我想要一个瘦的班级,像这样:

class MyEntity public int Id; public string Name; public string Email;

当我查询时,我想创建我的瘦对象的实例,显然,我可以这样做:

from x in MyEntity
select new MyEntity Id = x.Id, Name = x.Name, Email = x.Email ;

但我经常这样做,每次输入属性都非常乏味(而且容易出错,因为我可能会忘记一个)。

所以我正在尝试做这样的事情:

from x in MyEntity
select x.ToLiteEntity();

但我不知道如何编写ToLiteEntity 以便它创建一个添加到查询中的表达式,以便它知道从数据库中只选择所需的列。我该怎么做?

【问题讨论】:

如果您根本不使用项目中的其他列,为什么要在项目中一开始就引用它们呢?还是它们在数据库中没有默认值,所以没有它们就无法创建新行? 因为 EF 模型生成器会创建它们。我可以删除它们,但有时我必须重新生成,我会丢失这些编辑。 如果您的数据库架构与您的 EF 模型不匹配,最好不要使用模型生成器。 您的所有实体都是从MyEntity继承吗? 【参考方案1】:

您可以将其抽象到数据库之上的一层。当你想检索你的“精简”对象时,调用一个单独的方法:

public IQueryable<MyEntity> GetLiteMyEntities(DbContext c, string Name) // your implementation of DbContext, not actually DbContext

    return from me in c.MyEntity 
        select new MyEntity Id = x.Id, Name = x.Name, Email = x.Email ;

编辑:如果您需要过滤不想返回的其他字段,您可以先编写过滤查询,然后使用 采用 IQueryable 的方法:

public IQueryable<MyEntity> GetLiteMyEntities(IQueryable<MyEntity> query)

    return from me in query 
        select new MyEntity Id = x.Id, Name = x.Name, Email = x.Email ;


// build your filter first
from x in MyEntity 
where x.someSpecialID == 42
select x;

// then pass it to get your lite object
var lite = GetLiteMyEntities(x);

更好的是,让它成为一个扩展方法:

public IQueryable<MyEntity> GetLiteMyEntities(this IQueryable<MyEntity> query)

    return from me in query 
        select new MyEntity Id = x.Id, Name = x.Name, Email = x.Email ;


var lite = (from x in MyEntity 
where x.someSpecialID == 42
select x).GetLiteMyEntities();

【讨论】:

这很好,虽然一个缺点是 Lite 对象不仅必须包含您想要返回的所有字段,还必须包含您可能想要在 Where 子句中使用但不能返回的任何字段。 @JoshuaFrank 查看我的编辑,您可以编写查询并使用它们,直到需要它才会执行(ToList、迭代等)【参考方案2】:

您可以使用 AutoMapper 中的 Queryable Extensions

.ProjectTo() 将告诉 AutoMapper 的映射引擎 向 IQueryable 发出一个 select 子句,通知实体 只需要查询Item的Name列的框架 表,就像您手动将 IQueryable 投影到 带有 Select 子句的 OrderLineDTO。

【讨论】:

我在使用派生类(多态性)时遇到了这个问题。首先得到一个堆栈溢出异常,然后切换到使用 ProjectUsing 方法,但它无法使用抽象基类。

以上是关于如何创建可重用的实体框架投影表达式?的主要内容,如果未能解决你的问题,请参考以下文章

创建实体时的表名(包含/正则表达式) - 实体框架 - 表前缀

有没有办法在 lambda 表达式树中使用“动态”?

BIM工程信息管理系统-EF实体框架数据操作基类

如何在实体框架查询中使用多表达式方法[重复]

实体框架从表达式生成错误的参数类型

play框架用起来