使用导航加载实体 2 层深度
Using navigation to load entity 2 level deep
我有一个class
public class Level1
{
public int Id {get; set;}
public virtual List<Level2> Level2List {get; set;}
}
public class Level2
{
public int Id {get; set;}
public int Level3Id {get; set;}
public virtual Level3 Level3 {get; set;}
}
public class Level3
{
public int Id {get; set;}
public string Name {get; set;}
}
使用导航属性我可以像这样加载 List<Level2>
var myList = _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List);
但是如何加载 Level3 及其与 Level2 关联的属性?
PS: 延迟加载是不可能的。
这是Getsingle
函数
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
item = GetFilteredSet(context, navProps).AsNoTracking().FirstOrDefault(where);
return item;
}
使用 include 怎么样?
var mylevel1s = _db.Level1(x=>x.Id == Level1Id).Include(x=> x.Level2List.Select(a=>a.Level3));
你的GetSingle
方法应该是这样的:
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
{
IQueryable<T> query = context.Set<T>();
//Include the navigations properties as part of the query
if (navProps!= null)
{
query = navProps.Aggregate(query, (current, include) => current.Include(include));
}
item = query.Where(where).FirstOrDefault();
}
return item;
}
我不知道你在 GetFilteredSet
方法中做了什么,但我想你可以在方便时重新组织上面显示的代码。包含不止一级导航的关键。 EF 中的属性使用 Include
方法。当您使用此方法时,您将加载导航。属性作为查询的一部分(检查 link 中的预加载部分)。现在,有两种包含方法:
-
使用此方法需要传递导航路径。您想要作为字符串加载的属性,例如,在您的情况下,它将是:
context.Set<Level1>.Include("Level2List.Level3");
DbExtensions.Include extension method
这是我在上面的代码中使用的方法,您可以使用 lambda 表达式指定要包含的相关对象。恕我直言,这是最好的变体,因为它是强类型的,如果你改变一些导航。实体中的属性名称,您还将收到编译错误。在我上面分享的 link 中,您可以看到所有可用于包含不同级别导航的模式。属性。
context.Set<Level1>.Include(l1=>l1.Level2List.Select(l2=>l2.Level3));
回到最初的问题,现在您可以使用 GetSingle
方法以这种方式包含多个级别:
var entity= _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List.Select(l2=>l2.Level3));
我有一个class
public class Level1
{
public int Id {get; set;}
public virtual List<Level2> Level2List {get; set;}
}
public class Level2
{
public int Id {get; set;}
public int Level3Id {get; set;}
public virtual Level3 Level3 {get; set;}
}
public class Level3
{
public int Id {get; set;}
public string Name {get; set;}
}
使用导航属性我可以像这样加载 List<Level2>
var myList = _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List);
但是如何加载 Level3 及其与 Level2 关联的属性?
PS: 延迟加载是不可能的。
这是Getsingle
函数
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
item = GetFilteredSet(context, navProps).AsNoTracking().FirstOrDefault(where);
return item;
}
使用 include 怎么样?
var mylevel1s = _db.Level1(x=>x.Id == Level1Id).Include(x=> x.Level2List.Select(a=>a.Level3));
你的GetSingle
方法应该是这样的:
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
{
IQueryable<T> query = context.Set<T>();
//Include the navigations properties as part of the query
if (navProps!= null)
{
query = navProps.Aggregate(query, (current, include) => current.Include(include));
}
item = query.Where(where).FirstOrDefault();
}
return item;
}
我不知道你在 GetFilteredSet
方法中做了什么,但我想你可以在方便时重新组织上面显示的代码。包含不止一级导航的关键。 EF 中的属性使用 Include
方法。当您使用此方法时,您将加载导航。属性作为查询的一部分(检查 link 中的预加载部分)。现在,有两种包含方法:
-
使用此方法需要传递导航路径。您想要作为字符串加载的属性,例如,在您的情况下,它将是:
context.Set<Level1>.Include("Level2List.Level3");
DbExtensions.Include extension method
这是我在上面的代码中使用的方法,您可以使用 lambda 表达式指定要包含的相关对象。恕我直言,这是最好的变体,因为它是强类型的,如果你改变一些导航。实体中的属性名称,您还将收到编译错误。在我上面分享的 link 中,您可以看到所有可用于包含不同级别导航的模式。属性。
context.Set<Level1>.Include(l1=>l1.Level2List.Select(l2=>l2.Level3));
回到最初的问题,现在您可以使用 GetSingle
方法以这种方式包含多个级别:
var entity= _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List.Select(l2=>l2.Level3));