c# - 带有 Contains 的 Linq 查询仅适用于 IQueryable 位于外部变量中

标签 c# asp.net entity-framework linq-to-entities iqueryable

我正在使用带有 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/

相关文章:

c# - WaitHandle 背后的基本概念是什么?

php - 我们应该使用什么技术来防止通过粘贴 cookie 自动登录?

c# - 如何在一对多关系 EF 4.3.1 的导航集合中删除后正确清理

c# - EF6 - 使用可为 null 的属性(外键、TPH)时 SQL 查询无效

c# - 单元测试 EF DbUpdateConcurrencyException 处理

c# - WPF - 仅从用户点击触发 comboBox SelectedIndexChanged

c# - 如何在 C# 中使用 BinaryFormatter 更改反序列化的顺序?

ASP.NET核心API : How to use MySQL

c# - 在 rowcommand 上发送 HTTP header 后,服务器无法设置内容类型

asp.net - <% %> 和 <%=%> 有什么区别?