我怎样才能使用 EF6 获得相对实体的计数

How could I get a Relative Entity's count using EF6

我有一个名为“Client”的实体和另一个名为“Card”的实体。

一个客户可能有很多卡片

我的客户实体看起来像这样:

public class Client{
    public virtual ICollection<Card> Cards {get; set;}
}

现在我想在 WPF 的 DataGrid 中显示 Client 数据,我想获得 Cards Count 数据,所以我添加一个 属性 到 Client 实体,像这样:

public class Client{
    public virtual ICollection<Card> Cards {get; set;}

    public int CardCount
    {
        return Cards.Count;
    }
}

然后我用 Linq 查询数据并绑定到视图

var query = from n in db.Clients select n;

当我 运行 应用程序时,我在 return Cards.Count; 行得到了一个异常;

System.ObjectDisposedException
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

那么我怎样才能正确得到卡片数

如果您没有具体化检索到的查询,您会得到一个 ObjectDisposedException。在以下情况下,仅当您第一次访问 GetNonMaterialized 中的列表时才会执行查询,而不是在离开该方法之前。事实上 db 由于范围丢失而被处置。

public IEnumerable<Client> GetNonMaterialized()
{
    return from n in db.Clients select n;
}

在以下情况下,查询在离开方法之前执行。

public IEnumerable<Client> GetMaterialized()
{
    return (from n in db.Clients select n).ToList();
}

始终确保执行查询 before 退出 ObjectContext.

的范围

如果您想知道查询是否执行以及何时启用EF的Logging。

How can I turn off Entity Framework 6.1 logging?

有一种比此处显示的其他答案更简单的方法。还请注意

等解决方案
var client = db.Clients.FirstOrDefault(c=> c.Id = someid); //get a client
if (client != null)
{
    cardCount = client.Cards.Count;
}

会导致一个名为 Select N+1 的问题。如果有兴趣,请阅读它,但简而言之,它意味着以下内容:

因为您不仅对一个确切的客户感兴趣,而且还想显示 N 个客户,所以您需要执行一 (1) 个查询以仅获取客户。然后,通过执行 FirstOrDefault 操作,您实际上对每个 Client 记录执行一 (1) 次额外的数据库往返,这会导致额外的 N * 1 = N 次往返。这意味着,如果您只查询 Clients 而没有任何相关数据,您可以在一次查询中获得任意多条客户记录。但是通过为它们中的每一个获取相关数据 one-by-one,你进行了太多的数据库往返。

这里有一个解决这个问题的方法,就是使用连接和投影。您可以在一次数据库访问中获取所需的所有数据:

using (var context = GetDbContext())
{
    return context.Clients.Select(cli => new YourViewModel
    {
        Name = cli.FullName,
        // Other prop setters go here
        CardCount = cli.Cards.Count
    }).Skip((page - 1) * pageSize).Take(pageSize).ToList();
}

您可能想知道,到底有什么区别?好吧,在这里,您使用的不是物化对象,正如其他人在这里所说的那样,而是使用 DbContext。通过对其应用适当的 LINQ 运算符(请注意,这不仅适用于 DbContext,而且适用于任何 IQueryable(很明显,如果您在已经 [=34] 上调用 AsQueryable() =] collection but whatever)), LINQ to Entities 可以构造一个适当的 SQL 来连接表并投影结果,因此您可以一次性获取所有需要的数据。请注意,LINQ to Entities 能够将 cli.Cards.Count 转换为正确的 SQL Count 语句。

您无需像这样加载实体即可获得计数:

using (var context = new MyContext()) 
{ 
     var client = context.Client.Find(clientId); 

     // Count how many cards the client has  
     var cardsCount = context.Entry(client) 
                      .Collection(b => b.Cards) 
                      .Query() 
                      .Count(); 
}

更多信息on MSDN page