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

发布于 2024-12-08 15:22:29 字数 1831 浏览 0 评论 0原文

我正在将实体框架与 Linq to Entities 结合使用,尝试从数据库中选择一些数据。当我创建使用 IQueryable.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;

如果你仔细观察,你会发现我在这段代码中的 wherevolumes > 条件。如果我复制此变量的内容并将其粘贴到 metrics 变量中,则会出现下面的代码,它会引发错误:“无法创建“CalculadoraRFS.Models”类型的常量值.Domain.VolumeAditivo'。在此上下文中仅支持原始类型('例如 Int32、String 和 Guid')。”

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 指出的那样,我发现存储库模式或 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;

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

I am using Entity Framework with Linq to Entities, trying to select some data from my database. When I create a Linq query that uses the method IQueryable<int>.Contains, it can only filter the data if I use an external variable! Let me show some example.

This block of code, works perfectly:

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;

If you take a good look, you can see I use the variable volumes inside this snippet, in the where condition. If I copy the contents of this variable and paste it inside the metrics variable, leading to the code below, it raises the error: "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;

How can I variable substitution cause such error?! Am I doing (certainly) something wrong?
Thank you!


UPDATE:

Actually, I find out that the Repository Pattern or DbContext seems to be the problem, as @jhamm pointed out. The snippet below doesn't work either:

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;

But the snippet below works. I just took the context out of the UnitOfWork class, though it is very simply defined there: 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;

Now I'm really confused about this stuff! Wasn't it supposed to work as expected?!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

温馨耳语 2024-12-15 15:22:29

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

如果您在组合 LINQ 语句时仍然遇到问题,那么下一步最好是尝试不使用存储库对象的实体框架对象。如果此查询有效,则您的存储库对象可能有问题。

// 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 个测试/问题的混合和匹配,我们应该越来越接近答案。当我遇到这样的问题时,我会尝试用可验证的答案来问自己问题。基本上,我尝试使用科学方法来缩小问题范围以找到解决方案。

I used LINQPad to use my EF Database First model on a similar type of query. Both the combined and separate queries gave the same correct results and generated the same SQL. Here is a link on how to use LINQPad with Entity Framework. One difference could be the use of the Repository Pattern, I am not using one. I would recommend testing with the first query to see what SQL is generated. After you run a query, LINQPad has a SQL tab that may help troubleshoot what is going on by looking at the generated SQL.

If you are still having trouble with the combined LINQ statement, a good next step would be to try the Entity Framework object without the Repository objects. If this query works, there may be something wrong with your Repository objects.

// 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;

To find out where the issue lies, I would next use the MetricRepository with the VolumeAdditive EF object.

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;

Then I would switch them to use the Metric EF object with the VolumeAdditiveRepository.

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;

Based on the generated SQL and which queries work, I think this should help point you in the right direction. This is based on removing parts of the problem until it works. Then adding them back in until they break to indicate where the issue is. These steps should be done using small incremental changes to minimize the problem space.


Update:

Based on the new information, lets try to divide the new information into new questions that we need to answer.

Maybe the LINQ expression is not able to figure out what to do with the work._context.VolumeAdditive in the where clause. So lets test this theory by using the following. This sets the context to a single variable instead of using 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;

Maybe using a let statement to define the MetricID's could resolve this issue.

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;

Based on the results of these tests and mixing and matching the previous 3 tests/questions, we should be getting closer to the answer. When I come up against issues like this, I try to ask my self questions with verifiable answers. Basically, I try to use the Scientific Method to narrow down the issue to find a resolution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文