【问题标题】:entity-framework, how to project into a list实体框架,如何投影到列表中
【发布时间】:2009-09-21 08:15:02
【问题描述】:

我已经在几个项目中使用了 linq2sql,但我决定是时候尝试一下 EF,因为它应该更强大、更好。有几件事真的很烦人。 其中之一是将结果投影到列表中,这在 l2sql 中效果很好,但在 EF 中效果不佳。

public class bo.Transaction
{
  public long Id { get; set; }
  public List<bo.Line> Lines { get; set; }
}

public class bo.Line
{
  public int RowNo { get; set; }
  public string Descripton{ get; set; }
  public double Amount{ get; set; }
}

return from t in Db.Transaction.Include("Lines")
       select new bo.Transaction {
         Id = t.Id,
         Lines = t.Lines.OrderBy(l => l.RowNo).ToList(),
       };

但是,ToList() 调用失败,并显示消息“System.NotSupportedException:LINQ to Entities 无法识别方法 'List[bo.Line] ToListLine' 方法,并且此方法无法转换为存储表达式..”。

有什么办法可以解决这个问题?还是我只需要使用 ienumerable 而不是列表?

【问题讨论】:

  • 一般来说,尽可能选择 IList 而不是 List。

标签: c# .net linq entity-framework


【解决方案1】:
return (from t in Db.Transaction.Include("Lines")
       select new bo.Transaction {
         Id = t.Id,
         Lines = t.Lines.OrderBy(l => l.RowNo),
       }).ToList();

Linq 查询不支持列表,所以我们对枚举结果执行此操作。不过,它确实会强制 Query 在那一刻立即执行。返回 IEnumerable 会使查询的执行延迟更长的时间。 (基本上直到您要访问数据的那一刻。)

【讨论】:

  • "Include" 在这里完全没有必要。 LINQ to Entities 会为您解决这个问题,因为您正在投影。否则正确 (+1)
【解决方案2】:

这是在黑暗中的尝试,但您的项目是否引用了 System.Core dll?如果没有这个引用,.ToList() 扩展方法将不可用。

此外,正如 Workshop Alex 指出的那样,您的 .ToList() 调用位于错误的位置。

【讨论】:

  • 它的EF翻译器不支持ToList(),引用正确
【解决方案3】:

Workshop Alex 写的是对的,但让我解释一下它背后的理论:
您可能知道,当您编写 LINQ-to-Entities 查询时,您正在编写将针对您的数据库执行的内容。为了以有效的方式完成此操作,查询将被转换为 SQL 并针对您的数据库运行,而不是获取每个实体、针对给定条件对其进行测试、对结果进行排序和此类操作。
然而,任何有效的 C# 都可以用于您的查询这一事实并不意味着您可以编写的所有代码都可以转换为 SQL。没有翻译的代码的显着示例是混合数据访问和实体类反射的查询,或者 - 就像您的情况一样 - 使用特殊的 .NET 数据类型的代码。这种查询通常可以分两步执行,一个针对数据库操作,一个针对 RAM 中的实体。虽然这可能不会像您希望的那样高效和干净,但由于我个人不喜欢存储过程,我仍然发现它比您可能采用的大多数其他方法要好得多,前提是您的约束允许您做出选择。

编辑:
确实可以通过这种方式在数据库上运行部分查询和在内存中运行部分查询来轻松处理该场景:

Db.Transaction.Include("Lines").Select(t => new bo.Transaction { t.Id, Lines = t.Lines.OrderBy(l => l.RowNo) }).AsEnumerable().Select(t => new bo.Transacton { t.Id, Lines = t.Lines.ToList()});

AsEnumerable 调用有助于确保第二个 Select 是针对已从数据库中获取的一组对象运行的,因此不再存在将 ToList 转换为 SQL 的问题。

【讨论】:

  • 我很清楚 linq 查询的执行方式和时间。那不是这里的问题。问题是我无法将子查询投影到其他对象的列表中。与在内存中执行部分查询相比,似乎 ef 更倾向于抛出运行时异常。
  • 这真的是关于翻译以及你的堆栈的哪一部分运行查询,因为你的问题实际上是你不能急切地从你的 LINQ 查询中获取一个集合,那是因为 SQL 真的不知道可调整大小的数组。当然你得到的异常不是很清楚,但你必须考虑到从你的查询生成的 SQL 不会在你的 dbms 以外的任何地方运行或验证,所以如果由于表达式生成了错误的 SQL没有翻译,这就是你会得到的例外。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-18
相关资源
最近更新 更多