带包含的Linq查询仅适用于IQueryable是在外部变量中

tyr*_*ron 7 c# asp.net linq-to-entities entity-framework iqueryable

我正在使用实体框架与Linq to Entities,尝试从我的数据库中选择一些数据.当我创建使用该方法的Linq查询时,IQueryable<int>.Contains如果我使用外部变量,它只能过滤数据!让我举一些例子.

这段代码完美无缺:

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;
Run Code Online (Sandbox Code Playgroud)

如果您仔细观察,您可以看到我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;
Run Code Online (Sandbox Code Playgroud)

我如何变量替换导致这样的错误?!我(肯定)做错了吗?
谢谢!


更新:

实际上,我发现Repository Pattern或DbContext似乎是问题所在,正如@jhamm指出的那样.下面的代码段不起作用:

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;
Run Code Online (Sandbox Code Playgroud)

但下面的代码段可行.我刚从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;
Run Code Online (Sandbox Code Playgroud)

现在我真的很困惑这个东西!它不应该按预期工作吗?!

jha*_*amm 6

我使用LINQPad在类似类型的查询上使用我的EF Database First模型.组合和单独的查询都给出了相同的正确结果并生成了相同的SQL.以下是有关如何使用LINQPad和Entity Framework的链接.一个区别可能是使用存储库模式,我没有使用它.我建议使用第一个查询进行测试,以查看生成的SQL.运行查询后,LINQPad有一个SQL选项卡,可以通过查看生成的SQL来帮助解决发生的问题.

如果您仍然遇到组合LINQ语句的问题,那么下一步就是尝试没有Repository对象的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;
Run Code Online (Sandbox Code Playgroud)

为了找出问题所在,接下来我将使用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;
Run Code Online (Sandbox Code Playgroud)

然后我将它们切换为使用带有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;
Run Code Online (Sandbox Code Playgroud)

基于生成的SQL以及查询的工作原理,我认为这有助于指明您正确的方向.这是基于删除部分问题直到它工作.然后将它们重新添加,直到它们断开以指示问题所在.应使用小的增量更改来完成这些步骤,以最大限度地减少问题空间.


更新:

根据新信息,我们尝试将新信息划分为我们需要回答的新问题.

也许LINQ表达式无法弄清楚如何处理work._context.VolumeAdditivewhere子句.因此,让我们使用以下方法测试这个理论.这将上下文设置为单个变量,而不是使用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;
Run Code Online (Sandbox Code Playgroud)

也许使用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;
Run Code Online (Sandbox Code Playgroud)

根据这些测试的结果,混合并匹配前面的3个测试/问题,我们应该更接近答案.当我遇到这样的问题时,我试着用可验证的答案问我的自我问题.基本上,我尝试使用科学方法缩小问题范围以找到解决方案.