jpa*_*aya 5 c# linq entity-framework
尝试优化查询时,我遇到EF6问题.考虑这个有一个集合的类:
public class Client
{
... a lot of properties
public virtual List<Country> Countries { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
您可能知道,使用延迟加载我有这个n + 1问题,当EF试图为每个客户端获取所有国家/地区时.
我试图使用Linq投影; 例如:
return _dbContext.Clients
.Select(client => new
{
client,
client.Countries
}).ToList().Select(data =>
{
data.client.Countries = data.Countries; // Here is the problem
return data.client;
}).ToList();
Run Code Online (Sandbox Code Playgroud)
这里我使用两个选择:第一个用于Linq投影,因此EF可以创建SQL,第二个用于将结果映射到Client类.原因是因为我正在使用一个返回的存储库接口List<Client>.
尽管查询是使用其中的国家生成的,但当我尝试渲染整个信息时,EF仍在使用延迟加载(相同的n + 1问题).避免这种情况的唯一方法是删除虚拟访问器:
public class Client
{
... a lot of properties
public List<Country> Countries { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我对此解决方案的问题是我们仍然希望将此属性设置为虚拟.此优化仅对应用程序的特定部分是必需的,而在其他部分我们希望具有此延迟加载功能.
我不知道如何"通知"EF关于这个属性,这个属性已经通过这个Linq投影延迟加载了.那可能吗?如果没有,我们还有其他选择吗?的n + 1个问题使得应用到需要几秒钟来加载像1000行.
编辑
谢谢你的回复.我知道我可以使用Include()扩展来获取集合,但我的问题是需要添加一些额外的优化(我很抱歉没有发布完整的示例,我认为收集问题就足够了):
public class Client
{
... a lot of properties
public virtual List<Country> Countries { get; set; }
public virtual List<Action> Actions { get; set; }
public virtual List<Investment> Investments { get; set; }
public User LastUpdatedBy {
get {
if(Actions != null) {
return Actions.Last();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我需要渲染客户端,有关上次更新的信息和投资数量(Count()),Include()我实际上需要从数据库中获取所有信息.但是,如果我使用像投影一样
return _dbContext.Clients
.Select(client => new
{
client,
client.Countries,
NumberOfInvestments = client.Investments.Count() // this is translated to an SQL query
LastUpdatedBy = client.Audits.OrderByDescending(m => m.Id).FirstOrDefault(),
}).ToList().Select(data =>
{
// here I map back the data
return data.client;
}).ToList();
Run Code Online (Sandbox Code Playgroud)
我可以减少查询,只获取所需的信息(在LastUpdated的情况下,我需要将属性更改为getter/setter,这不是一个大问题,因为它仅用于应用程序的这个特定部分).
如果我使用这种方法的Select()(投影然后映射),Include()EF不考虑该部分.
如果我理解正确的话你可以试试这个
_dbContext.LazyLoading = false;
var clientWithCountres = _dbContext.Clients
.Include(c=>c.Countries)
.ToList();
Run Code Online (Sandbox Code Playgroud)
这将获取
Client并仅包含它Countries。如果禁用延迟加载,则不会从查询中加载其他集合。除非您指定包含或投影。
仅供参考:投影和 Include() 不能一起工作,请参阅此答案如果您进行投影,它将绕过包含。 /sf/answers/501775781/