我正在使用带有 Linq to Entities 的 Entity Framework ,试图从我的数据库中选择一些数据。当我创建一个使用方法 IQueryable<int>.Contains
的 Linq 查询时,如果我使用外部变量,它只能过滤数据!让我举个例子。
这段代码完美运行:
var volumes = (from v in work.VolumeAdditiveRepository.All
where v.AdditivesID == AdditivesID
select v.MetricID);
var metrics =
from m in work.MetricRepository.All
where !volumes.Contains(m.ID)
select m;
如果仔细观察,您会发现我在这段代码中使用了变量 volumes
,在 where
条件下。如果我复制此变量的内容并将其粘贴到 metrics
变量中,导致下面的代码,它会引发错误:"Unable to create a constant value of type 'CalculadoraRFS.Models.Domain.VolumeAditivo'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."
。
var metrics =
from m in work.MetricRepository.All
where !(from v in work.VolumeAdditiveRepository.All
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
变量替换怎么会导致这样的错误?!我(肯定)做错了什么吗?
谢谢!
更新:
实际上,正如@jhamm 指出的那样,我发现 Repository Pattern 或 DbContext 似乎是问题所在。下面的代码片段也不起作用:
var query = from m in work._context.Metric
where !(from v in work._context.VolumeAdditive
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
但下面的代码片段有效。我只是从 UnitOfWork 类中取出上下文,尽管它在那里的定义非常简单:public CalculadoraRFSContext _context = new CalculadoraRFSContext();
。
var _context = new CalculadoraRFSContext();
var query = from m in _context.Metric
where !(from v in _context.VolumeAdditive
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
现在我对这些东西真的很困惑!它不是应该按预期工作吗?!
最佳答案
我用了LINQPad在类似类型的查询中使用我的 EF Database First 模型。组合查询和单独查询都给出了相同的正确结果并生成了相同的 SQL。这是有关如何 use LINQPad with Entity Framework 的链接.一个区别可能是存储库模式的使用,我没有使用它。我建议使用第一个查询进行测试以查看生成的 SQL。运行查询后,LINQPad 有一个 SQL 选项卡,可以通过查看生成的 SQL 来帮助解决正在发生的问题。
如果您仍然无法使用组合的 LINQ 语句,下一步最好是尝试不使用存储库对象的 Entity Framework 对象。如果此查询有效,则您的 Repository 对象可能有问题。
// Guessing that Metric and VolumeAdditive are the EF Entities
// LINQPad database dropdown sets the context so they were not set it in these samples
var metrics =
from m in Metric
where !(from v in VolumeAdditive
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
为了找出问题所在,接下来我将使用 MetricRepository 和 VolumeAdditive EF 对象。
var metrics =
from m in work.MetricRepository.All
where !(from v in VolumeAdditive
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
然后我会将它们切换为使用带有 VolumeAdditiveRepository 的 Metric EF 对象。
var metrics =
from m in Metric
where !(from v in work.VolumeAdditiveRepository.All
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
根据生成的 SQL 和哪些查询有效,我认为这应该可以帮助您指明正确的方向。这是基于消除问题的一部分直到它起作用。然后将它们重新添加,直到它们断开以指示问题所在。这些步骤应该使用小的增量更改来完成,以最大限度地减少问题空间。
更新:
根据新信息,我们尝试将新信息分解为我们需要回答的新问题。
也许 LINQ 表达式无法确定如何处理 where 子句中的 work._context.VolumeAdditive
。因此,让我们使用以下内容来测试该理论。这会将上下文设置为单个变量,而不是使用 work._context。
var _context = work._context;
var query = from m in _context.Metric
where !(from v in _context.VolumeAdditive
where v.AdditivesID == AdditivesID
select v.MetricID).Contains(m.ID)
select m;
也许使用 let 语句来定义 MetricID 可以解决这个问题。
var metrics =
from m in work.MetricRepository.All
let volumes = from v in work.VolumeAdditiveRepository.All
where v.AdditivesID == AdditivesID
select v.MetricID
where !volumes.Contains(m.ID)
select m;
根据这些测试的结果以及混合和匹配前 3 个测试/问题,我们应该会更接近答案。当我遇到这样的问题时,我会尝试用可验证的答案来问自己问题。基本上,我尝试使用科学方法缩小问题范围以找到解决方案。
关于c# - 带有 Contains 的 Linq 查询仅适用于 IQueryable 位于外部变量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7675791/