使用LINQ to Entities将派生类强制转换为基类

本文关键字:转换 基类 派生 LINQ to Entities 使用 | 更新日期: 2023-09-27 18:14:14

我有两个数据库表,一个用于保存已完成的项,另一个用于保存未完成的项。这两个表在结构上是相同的。在某些情况下,我只想查询其中一个表,但在其他情况下,我想查询两个表的连接。

public abstract class SomeBase
{
    public int Id {set;get;}
    public string Item1 {set;get;}
    public string Item2 {set;get;}
}
public class A : SomeBase
{
}
public class B : SomeBase
{
}

Mapping (Fluent API)

public class SomeDatabase : DbContext
{
    public DbSet<A> As {set;get;}
    public DbSet<B> Bs {set;get;}
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<A>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("ATable", "SomeSchema");
        }
        modelBuilder.Entity<B>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("BTable", "SomeSchema");
        }
    }
}

使用这个设置,我可以单独查询两个表,就像这样

var db = new SomeDatabase();
var a = db.As;
var b = db.Bs;

当我试图把这两者结合起来的时候,我不太明白语法。下面答案中的一个解决方案涉及使用.AsEnumerable进行强制转换,但这不是我想要的,因为它立即计算。

db.As.AsEnumerable().Concat<SomeBase>(db.Bs);
db.As.Cast<SomeBase>().Concat(db.Bs.Cast<SomeBase>());

如何连接数据库站点上相同的两个派生类?

编辑:在最低级别,我得到这些错误

db.As.Cast<SomeBase>();
Unable to cast the type 'Test.Models.A' to type 'Test.Models.SomeBase'. LINQ to Entities only supports casting Entity Data Model primitive types.
db.As.OfType<SomeBase>();
'Test.Models.SomeBase' is not a valid metadata type for type filtering operations. Type filtering is only valid on entity types and complex types.

相关问题:如何结合2个不同的IQueryable/List/Collection与相同的基类?LINQ联合和协方差问题

使用LINQ to Entities将派生类强制转换为基类

简单定义一个

DbSet<SomeBase> Bases { get; set;}

属性访问基类的所有实例。框架应该以正确的方式组合查询(联合),以包括来自两个表的实例。

要了解更多细节,请查看以下文章:http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines.aspx

(使用TPC继承策略)

也许有更优雅的方式,但我想联合应该做:

db.As.Select(x => new { x.Id, x.Item1, x.Item2 } )
.Union(db.Bs.Select(x => new { x.Id, x.Item1, x.Item2 }));

如果你想包含一些来自a和b的字段,那么它应该看起来像:

db.As.Select(x => new { x.Id, x.Item1, x.Item2, x.Afield, Bfield = null } )
.Union(db.Bs.Select(x => new { x.Id, x.Item1, x.Item2, AField = null, x.Bfield }));

如何:

var concatenatedSet = db.As.Local.OfType<SomeBase>().Concat(db.Bs.Local.OfType<SomeBase());