【问题标题】:Entity Framework: multiple from is generating cross join实体框架:多个 from 正在生成交叉连接
【发布时间】:2016-03-24 23:30:08
【问题描述】:

我是 Entity Framework 的新手,我正在处理查询并找到了解决方案,但在使用 LINQPad 进行了一些调查后,我不喜欢生成的 SQL。

Linq 查询是:

from p in Person
from pcc in p.PersonCreditCard
group p by new { pcc.CreditCard.CardType } into g
select new
{
     cname = g.Key.CardType,
     cptPerson = g.Count()
}

生成的sql查询是

SELECT COUNT(*) AS [cptPerson], [t2].[CardType] AS [cname]
FROM [Person].[Person] AS [t0]
CROSS JOIN [Sales].[PersonCreditCard] AS [t1]
INNER JOIN [Sales].[CreditCard] AS [t2] ON [t2].[CreditCardID] = [t1].[CreditCardID]
WHERE [t1].[BusinessEntityID] = [t0].[BusinessEntityID]
GROUP BY [t2].[CardType

注意交叉连接。 据我所知,使用 CROSS JOIN 不是一个好主意。 为什么会这样?

我可以使用另一种语法来获得相同的结果(按信用卡类型计算人数)

【问题讨论】:

  • 如果您包含 Person 和 PersonCreditCard 的模型,将会很有用。我想这可能是一对多的关系,但我不想假设。如果是,那么您的映射可能已关闭,这肯定会解释它,因为 EF 不知道这两个实体在 DB 模型中是如何相关的。

标签: c# sql-server entity-framework linq


【解决方案1】:

尝试通过PersonCreditCard开始查询:

var query= context.PersonCreditCard.GroupBy(c=>c.CreditCard.CardType)
                                   .Select(g=>new {
                                                    cname = g.Key,
                                                    cptPerson = g.Count()
                                                  }
                                          );

更新

我猜在PersonCreditCard 实体中,您还可以引用Person,因此您可以像这样在查询中添加Where 调用:

var query= context.PersonCreditCard.Where(pc=>pc.Person.Name=="John")
                                   .GroupBy(c=>c.CreditCard.CardType)
                                   .Select(g=>new {
                                                    cname = g.Key,
                                                    cptPerson = g.Count()
                                                  }
                                          );

更新 2

我想我明白你的意思,如果你想在结果中包含属于每个组的人,你可以执行以下操作:

var query= context.PersonCreditCard.Where(pc=>pc.Person.Name=="John")
                                   .GroupBy(c=>c.CreditCard.CardType)
                                   .Select(g=>new {
                                                    cname = g.Key,
                                                    cptPerson = g.Count()
                                                    people=g.Select(pc=>pc.Person);
                                                  }
                                          );

【讨论】:

  • 是的,它给出了正确的数字......但它并没有完全回答这个问题。您通过消除 Person 表来回答它。我同意计算关系表中的条目数与计算 Person 的结果相同......但是如果我想计算 Firstname = John 的 Person 怎么办......你如何将它添加到该查询中?跨度>
  • 好吧,我的第一个查询是基于您期望使用查询获得的结果;)。检查我的更新,我在其中添加了您在评论中提到的条件
  • 好的,我重新回顾一下我刚才说的话。您可以添加一个能够使用 Person 属性的 .where。让我想想……也许你有答案了。
  • 我已经添加了另一个更新,如果您正在寻找,请告诉我。
  • 更新 2 很有趣......但更新 1 是我一直在寻找的(现在 :))。在更新 2 中,我知道它正在返回按组计算的人。因此,为每个组提供一个人员列表会很有趣(有助于深入研究)。但这对于我想做的事情来说太过分了。底线:实体框架不是 SQL :) 我将不得不忘记我在 SQL 中所知道的大部分内容才能使用 EF。
【解决方案2】:

如果你像这样映射你的多对多关系

class Person{
 ..more properties here

  public virtual ICollection<CreditCard> CreditCards{ get; set; }
}

class CreditCard{
 ..more properties here

  public virtual ICollection<Person> Persons{ get; set; }
}

你可以这样查询

int count = _context.Persons.GroupBy(p => p.CreditCards.Select(c=>c.CardType)).Count();

为您使用的任何内容更改 _context。

【讨论】:

  • 不,问题是 Persons 和 CreditCard 之间存在多对多关系。所以中间有一张 PersonCreditCard 表。所以 CardType 在 CreditCard 上,而不是 PersonCreditCard。而且我不能做 p.PersonCreditCard.CreditCard.CardType。
  • 你有一个实体来映射你的代码中的关系吗?或者您只有个人实体上的信用卡列表和信用卡上的个人列表?
  • 我使用的真实数据库是 AdventureWorks 2014(MS 演示数据库)。然后我使用“Entity Data Model Wizard”导入“Code First from Db”。所以简短的回答是:是的,我有一个实体来映射 Person 和 CreditCard 之间的关系,它被称为 PersonCreditCard。所以你的答案不起作用。
猜你喜欢
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
相关资源
最近更新 更多