繁体   English   中英

按实体类型的 EF 条件包含

[英]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)
    ...
    ...
;

我知道我可以单独做,但我不想要,因为我有很多实体,我需要尽量减少数据库请求。

我不想使用延迟加载,因为这也会产生许多数据库请求。

如何做到这一点?

EF Core 在 2.1 及更高版本中支持此功能。 此处查看 Github 问题

var query = myContext.Mammals
    .Include(d => (d as Dog).Tail)
    .Include(b => (b as Bat).Wing)
    .Include(b => (b as Buffalo).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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM