我怎样才能使用 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。
我有一个名为“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。