【问题标题】:LINQ Select Method Issues With Fluent InterfaceFluent 接口的 LINQ Select 方法问题
【发布时间】:2010-07-07 15:54:46
【问题描述】:

我正在使用 LINQ-to-Entities。使用以下查询:

var x = from u in context.Users select new { u.Id, u.Name };

选择IdName 列。伟大的。

我正在尝试创建一个可以将 new { u.Id, u.Name} 作为参数传递的存储库,以允许客户端选择在 SELECT 语句中使用哪些列。

我正在尝试在我的存储库中使用“流利”界面而不是查询语法。基本上最后的调用是将 IQueryable 转换为 IList 并实际执行代码。我查看了 DynamicExpressions 库,但我不确定这是我想要采取的路线。使用查询语法可以做到,但流畅的界面不行?

编辑:对不起,我应该提到所有查询都封装在存储库中内部。因此,例如,我希望能够公开如下方法:

public void Project(Expression<Func<TEntity, TEntity>> fields)
{
    this.Projection = fields;
}

所以调用它就像:

using (DBContext context = new DBContext())
{
    IUserRepository repo = new UserRepository(context);
    repo.Project(u => new { u.Id, u.Name });
    repo.GetById(100);
}

GetById 的内部类似于ctx.Users.Where(u =&gt; u.Id == id).Select(this.Projection)

这样,调用代码可以选择返回哪些列。这样做的原因是因为也许我想返回一个 User 对象,但也许我只需要 Id 和 Name(因此通过网络返回的数据更少)。

问题是我显然无法将匿名类型转换为 User。如果我能做这样的事情会很酷:

repo.Project(u => new User() { Id = u.Id, Name = u.Name });

这意味着我不需要在类型上创建匿名。编辑:好的,这似乎只在返回的类型是 POCO 时才有效......呃。

EDIT2:我可能不得不采用 LINQ 方法。我在想的是拥有Expression&lt;Func&lt;TEntity, object&gt;&gt;(使用匿名类型),然后使用反射来获取属性列表。然后,使用 LINQ 构建一个字符串表达式。唯一的缺点是我真的不想使用 LINQ,因为它会增加一点开销(Reflection.Emit 等)。

【问题讨论】:

  • 为什么您试图将投影放入存储库中?你最好返回一个 IQueryable。然后,任何人都可以选择他们喜欢的任何列,并且惰性评估将负责使其在通过网络传输的内容方面变得高效。
  • 我不希望我的存储库因 IQueryable 而泄漏。见stackoverflow.com/questions/718624/…

标签: c# linq linq-to-entities


【解决方案1】:

恐怕我不太确定您实际上在问什么,但是使用点表示法(我认为您称之为流利界面的术语)很容易编写该查询:

var x = context.Users.Select(u => new { u.Id, u.Name });

正如 Adam 所说,如果您尝试创建以强类型方式将此元组作为值的东西,您将需要一个命名类型。您可以创建自己的,如果您使用的是 .NET 4,则可以使用 Tuple&lt;T1, T2&gt;

这似乎不符合你关于声称你可以用查询表达式做你想做的事情的问题……你能详细说明一下吗?

编辑:好的,现在我对你在说什么有了一些的想法......

...您应该使Project 方法采用Expression&lt;Func&lt;TInput, TOutput&gt;&gt; 类型的表达式树并返回使用TOutput 的内容 - 例如RepositoryProjection&lt;TOutput&gt;。这样匿名类型仍然可以有效地在您的代码中捕获 - 因此您可以稍后使用它(例如,在查询中添加额外的条件)。

【讨论】:

  • @TheCloudlessSky:我不完全相信我理解,但我已经用另一个想法编辑了我的答案。
  • 是的,这就是我的计划。现在这个 工作 但是当我使用实体而不是 POCO 进行项目时,我得到一个 NotSupportedException 与“无法在 LINQ to Entities 查询中构造实体或复杂类型'Data.Repositories.User' 。”作为消息:(。如果我使用 POCO,它工作得很好。我真的不想维护 two 类用户......这有点蹩脚。我在想只需使用object,然后使用 LINQ 库构建字符串...
  • 查看这篇文章了解我的意思:stackoverflow.com/questions/1338362/… 如果 Microsoft 快点,我可能会使用 Code-Only 支持。我现在只是不知道如何用它映射多对多......
  • @TheCloudlessSky:老实说,我认为我们现在有点超出了最初的问题......
  • 我当然是,我只是大声说话:) ...对不起!不管怎样,谢谢你的回答。
【解决方案2】:

使用不带类型名称的new 语法(正如您所做的那样)创建一个匿名类型。虽然这些很有用,但匿名类型不能暴露在定义它们的函数之外。如果您需要能够将该特定实体传递给另一个函数,则必须在代码中的某处定义具有这些属性的实际类,并将其作为查询的一部分实例化。例如:

public class MyUser
{
    public int Id { get; set; }
    public string Name { get; set; }
}

然后:

var x = from u in context.Users select new MyUser { Id = u.Id, Name = u.Name }; 

【讨论】:

  • 见我上面的编辑。我知道您发布的内容是可能的。这不是我想要做的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-08
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
相关资源
最近更新 更多