gpt4 book ai didi

c# - 为什么 Entity Framework 6 不支持 Discriminator 的显式过滤?

转载 作者:行者123 更新时间:2023-11-30 17:37:47 28 4
gpt4 key购买 nike

以下是用于演示该问题的小型 EF6 程序。

public abstract class Base
{
public int Id { get; set; }

public abstract int TypeId { get; }
}
public class SubA : Base
{
public override int TypeId => 1;
}
public class SubAA : SubA
{
public override int TypeId => 2;
}
public class SubB : Base
{
public override int TypeId => 3;
}
public class SubC : Base
{
public override int TypeId => 4;
}

public class DevartContext : DbContext
{
public virtual DbSet<Base> Bases { get; set; }

public DevartContext()
{

}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Base>()
.Map<SubA>(x => x.Requires(nameof(SubA.TypeId)).HasValue(1))
.Map<SubAA>(x => x.Requires(nameof(SubAA.TypeId)).HasValue(2))
.Map<SubB>(x => x.Requires(nameof(SubB.TypeId)).HasValue(3))
.Map<SubC>(x => x.Requires(nameof(SubC.TypeId)).HasValue(4));
}
}

public class Program
{
public static void Main(string[] args)
{
using (DevartContext ctx = new DevartContext())
{
// prevent model-changes from wrecking the test
ctx.Database.Delete();
ctx.Database.Create();

var result = ctx.Bases.Where(x => x.TypeId == 1);
// throws on materialization, why?
foreach (var entry in result)
{
Console.WriteLine(entry);
}
}
Console.ReadLine();
}
}

它的要点是:我们有一个 TPH 模型,它带有一个显式配置的鉴别器(在本例中为 TypeId)。然后我们尝试使用该 TypeId 查询特定子类型,因为在我们的假设示例中使用 is 运算符也会返回 SubAA,而不仅仅是 SubA。

显然,我可以将上面的代码修改为类似 Where(x => x is SubA && !(x is SubAA)) 但这显然会在我添加 SubAB 后立即中断,并且通过构建一个 exact-filter-linq-to-entities-helper-method 来自动化它显然非常慢,因为该方法必须进行大量的反射。更不用说上面生成的 SQL 是可怕的,因为 EF/My SQL Provider 没有正确优化它。

现在尝试执行上述操作会导致在查询具体化时抛出 NotSupportedException,这基本上表明因为 TypeId 不是实体的成员,所以我不能用它来过滤。

我四处寻找绕过这个问题的方法,但我能找到的最好的东西是自动生成 Where(x => x is SubA && !(x is SubAA)) 版本来解决这个问题,这很可能是我必须做的来解决这个问题。

所以我的问题是:为什么 EntityFramework 不支持这个?

最佳答案

这个灵魂如你所愿地工作,不要改变任何东西^^“永远不要改变正在运行的系统”:)

您可以使用枚举而不是整数,这为您的代码提供了更高的类型安全性!

static void Main(string[] args)
{
using (DevartContext ctx = new DevartContext())
{
// prevent model-changes from wrecking the test
ctx.Database.Delete();
ctx.Database.Create();
ctx.Bases.Add(new SubA());
ctx.Bases.Add(new SubAA());
ctx.Bases.Add(new SubB());

ctx.SaveChanges();

var result = ctx.Bases.Where(x => x.TypeId == 1);
// throws on materialization, why?
foreach (var entry in result)
{
Console.WriteLine(entry);
}
}
Console.ReadLine();
}


public abstract class Base
{
public int Id { get; set; }

public virtual int TypeId { get; protected set; }
}
public class SubA : Base
{
public override int TypeId { get;protected set; } = 1;
}
public class SubAA : SubA
{
public override int TypeId { get; protected set; } = 2;
}
public class SubB : Base
{
public override int TypeId { get; protected set; } = 3;
}
public class SubC : Base
{
public override int TypeId { get; protected set; } = 4;
}

public class DevartContext : DbContext
{
public DbSet<Base> Bases { get; set; }

public DevartContext()
{
}
}

数据库中的结果:

Id  TypeId  Discriminator
1 1 SubA
2 2 SubAA
3 3 SubB

关于c# - 为什么 Entity Framework 6 不支持 Discriminator 的显式过滤?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37432234/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com