[英]EF Conditional Include by Entity Type
请假设该架构:
public class Mammal
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Dog : Mammal
{
public int TailId { get; set; }
public Tail Tail { get; set; }
}
public class Bat : Mammal
{
public int WingId { get; set; }
public Wing Wing { get; set; }
}
public class Buffalo : Mammal
{
public virtual ICollection<Horn> Horns { get; set; }
}
public class Tail
{
public int Id { get; set; }
...
}
public class Wing
{
public int Id { get; set; }
...
}
public class Horn
{
public int Id { get; set; }
...
}
现在,我的上下文:
public class MyContext : DbContext
{
public DbSet<Mammal> Mammals { get; set; }
}
因此,我只想进行一个 sql 查询,并包含(并加载)所有嵌套实体,例如:
var query = myContext.Mammals
.IncludeIfTypeIs<Dog>(d => d.Tail)
.IncludeIfTypeIs<Bat>(b => b.Wing)
.IncludeIfTypeIs<Buffalo>(b => b.Horns)
...
...
;
我知道我可以单独做,但我不想要,因为我有很多实体,我需要尽量减少数据库请求。
我不想使用延迟加载,因为这也会产生许多数据库请求。
如何做到这一点?
你可以尝试这样的事情:
public static class Extensions
{
public static IQueryable<Mammal> IncludeExtraEntities<Mammal,T>(this IQueryable<Mammal> query, T derivedType) where T :Mammal
{
if (derivedType is Dog)
return query.Include("Tail");
if (derivedType is Bat)
return query.Include("Wing");
return query;
}
}
然后在你的数据库调用中:
var query = myContext.Mammals.IncludeExtraEntities(typeof(Dog));
也许这会奏效。
您可以创建一个方法来包含表达式列表。 (或者可能是一种扩展方法)。
public static IQueryable<Mammal> GetMammals(params Expression<Func<T, Object>>[] includeExps)
{
var query = context.Mammals.AsQueryable();
if (includeExps != null)
query = includeExps.Aggregate(query, (current, exp) => current.Include(exp));
return query;
}
然后,在您的代码中:
//Bat and Dog will be included here
var mammals = GetMammals(i => i.Bat, i => i.Dog);
希望能帮助到你!
问题是,如何加载派生类型的属性,只使用基类的 DbSet 而没有延迟加载? 恐怕这是不可能的。
但是,您可以这样做:
public class MyContext : DbContext
{
public DbSet<Mammal> Mammals { get; set; }
public DbSet<Dog> Dogs { get; set; }
public DbSet<Bat> Bats { get; set; }
}
您也可以简单地实现一种方法,针对您的每种类型
public static class Extensions
{
public static IQueryable<Dog> IncludeExtraEntities<Dog>(this IQueryable<Dog> query) where Dog : Mammal
{
return query.Include("Tail");
}
public static IQueryable<Bat> IncludeExtraEntities<Bat>(this IQueryable<Bat> query) where Bat: Mammal
{
return query.Include("Wing");
}
}
然后,您可以简单地调用:
myContext.Dogs.IncludeExtraEntities();
并且将调用取决于您的类型的方法。
您对Include
期望过高。 您在Include
输入的 lambda 表达式只是一个看起来过于智能的字符串提供程序。 在幕后,它的成员表达式被剖析以获取属性的名称,仅此而已。 该名称被输入到接受字符串参数的Include
方法中。 该方法执行实际工作。
lambda 表达式必须指向IQueryable
类型的导航属性。 你不能做...
myContext.Mammals.Include(d => d.Tail)
...因为Tail
不是基本类型的属性。 你只能做...
myContext.Mammals.OfType<Dog>().Include(d => d.Tail)
你能得到的最好的东西是
from m in context.Mammals
let tail = (m as Dog).Tail
let wing = (m as Bat).Wing
let horns= (m as Buffalo).Horns
select new { Mammal = m, tail, wing, horns }
由于所有内容都已转换为 SQL,因此您不必担心空引用异常。
我遇到了这样的问题,在这里我是如何解决它的:
public IEnumerable<OrderLine> GetAllOrderLinesData()
{
var _StockOrderLines = appContext.OrderLines.OfType<StockOrderLine>()
.Include(p => p.Order).Include(p => p.Product);
var _AnnualOrderLines = appContext.OrderLines.OfType<AnnualOrderLine>()
.Include(p => p.Order).Include(p => p.Customer);
return _StockOrderLines.ToList<OrderLine>().Union<OrderLine>(_AnnualOrderLines.ToList<OrderLine>());
}
你可以改变你的课程:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.