我有:
private Dictionary<int, Сolor[]> colorSet = new Dictionary<int, Сolor[]>()
{
{1, new Сolor[2] {Сolor.Red, Сolor.Green}},
{2, new Сolor[2] {Сolor.Yellow, Сolor.Blue}},
...
};
public class Graph
{
public Сolor Сolor { get; set; }
public ICollection<Point> Points { get; set; }
}
1)如何从List<Graph>
不为空的数据库中获取Points
?
List<Graph> graphs = context.Graphs.Where(g => g.Points.Count > 0).ToList()
2)如何执行?
List<Graph> graphs = context.Graphs.Where(g => colorSet[1].Contains(g.Color)).ToList()
例外是:
LINQ to Entities
无法识别方法&#39; ...&#39;方法,和 此方法无法转换为商店表达式。
答案 0 :(得分:2)
.Contains不能用在数据库上下文的.Where子句中。您可以使用.Any或.All进行比较。
List<Graph> graphs = context.Graphs.Where(g => colorSet[1].Any(c => c.Color == g.Color)).ToList()
答案 1 :(得分:1)
在EF中使用Enumerable.Contains()没有问题。它的String.Contains无法翻译。
第二个查询的问题在于您将LINQ运算符与对象访问代码混合,特别是colorSet[1]
。 LINQ to EF不会尝试执行此代码,也不知道如何将其转换为SQL。
解决方案是首先将colorSet值存储到变量:
var colors = colorSet[1];
List<Graph> graphs = context.Graphs
.Where(g => colors.Contains(g.Color))
.ToList();
LINQ to EF知道将Enumerable<T>.Contains()
翻译成AND Color IN (0,1)
子句
这假定您至少使用EF 5,Color
是枚举并指向自定义类,例如:
public enum Color
{
Red,
Green,
Blue,
Yellow
}
public class Point
{
public int Id { get; set; }
public int X { get; set; }
public int Y { get; set; }
}
<强>更新强>
关于第一个问题,您可以使用Any()
:
var graphs=context.Graphs
.Where(g => g.Points.Any())
.ToList();
Linq to EF将生成一个带有WHERE EXISTS
子句的SQL语句,例如
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Points] AS [Extent2]
WHERE [Extent1].[Id] = [Extent2].[Graph_Id]
)
这将返回包含点但不包含点本身的图形。当您尝试访问Graph对象的Points
属性时,这些将以惰性方式加载。如果您只想访问少数Points
属性,但如果您想要访问所有属性(N + 1问题),则会产生大量查询,这可以提高性能
如果您还要加载点数,则需要使用Include()
方法,例如:
var graphs=context.Graphs
.Include(g => g.Points)
.Where(g => g.Points.Any())
.ToList();
这将在图形和点之间执行左连接,并在单个查询中返回所有数据。