EntityFramework,没有判别器的继承类

时间:2016-08-18 14:43:01

标签: c# entity-framework entity-framework-6

是否可以使用POCO和EF来处理以下情况?我想有一个车辆表,有一些bool字段,如IsFast,IsVan,IsTruck,然后有一个车辆类,有一个FastVehicle,Van,Truck类继承自Vehicles类,没有自己的表,没有有鉴别领域?

类似的东西:

public class Vehicle
{
    public int Id {get; set;}
    public bool IsFast {get; set;}
    public bool IsTruck {get; set;}
    public bool IsVan {get; set;}
}

public class FastVehicle : Vehicle
{
    public FastVehicle(){
        IsFast = true;
    }
}

public class Van: Vehicle{
    public Van(){
        IsVan = true;
    }
}

public class Truck : Vehicle
{
    public Truck(){
        IsTruck = true;
    }
}

然后可能在我的DbContext中有类似的东西:

public virtual DbSet<Vehicle> Vehicles {get; set;}
public virtual DbSet<Van> Vans => (DbSet<Van>) Vehicles.Where(v => IsVan);
public virtual DbSet<Truck> Trucks => (DbSet<Truck>) Vehicles.Where(v => IsTruck);
public virtual DbSet<FastVehicle> FastVehicles => (DbSet<FastVehicle>) Vehicles.Where(v => IsFastVehicle);

这样的事情可能吗?或者出于某种原因这是个坏主意?我将如何重写OnModelCreating?

4 个答案:

答案 0 :(得分:2)

如果您没有每个班级的鉴别器或表格,则无法区分您的实体。

如果您在域模型中不需要bool属性,则实际上可以省略它们,因为Entity Framework默认使用Table per Hierarchy来映射继承。它会自动为您创建一个鉴别器列。 如果您将卡车对象添加到DbSet,它将相应地填充鉴别器colomn。

http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph

答案 1 :(得分:1)

我找到了一个生成数据库的解决方案,没有&#34; Discriminator&#34;柱。 此解决方案适用于我们希望保留数据库模式和表的情况,并且我们还希望在某些实体中添加更多字段。 想象一下,您希望拥有一个用于业务A的数据库,并且您希望将此dbcontext模型用于业务B,那么您可以在数据库和业务级别中一起考虑一种继承。

让我们去解决方案:

假设我们有

public class SampleDataContext : DbContext

{
   public DbSet<SampleUser> Users { get; set; }
}

[Table("Users")]
public class SampleUser
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string Family { get; set; }
  public string Username { get; set; }
  public override string ToString() => $"{Username} : {Name} {Family}";
}

我想在用户实体上创建一个带有额外字段的新数据上下文。新数据上下文也必须与我当前的业务逻辑层完全兼容。

我建议使用如下界面:

public interface IDbContext
{
    int SaveChanges();
}


public interface IDbSet<TE, in TId>
{
    TE Add();
    IQueryable<TE> All();
    TE Get(TId id);
    void Delete(TId id);
}

并像这样更改 SampleDataContext

public class SampleDataContext : DbContext,IUserDbContext
{

    public DbSet<SampleUser> Users { get; set; }


    private IDbSet<SampleUser, int> _userSet;
    public IDbSet<SampleUser, int> UserSet
        {
            get { return _userSet ?? (_userSet = new UserInterface() { Db = this }); }
            set { _userSet = value; }
        }
    public class UserInterface : IDbSet<SampleUser, int>
        {
            public SampleDataContext Db { get; set; }

            public SampleUser Add() => Db.Users.Add(new SampleUser());

            public IQueryable<SampleUser> All() => Db.Users;

            public SampleUser Get(int id) => Db.Users.Find(id);

            public void Delete(int id) => Db.Users.Remove(Get(id));
        }
}

还为用户业务添加界面:

public interface IUserDbContext : IDbContext
{
    IDbSet<SampleUser, int> UserSet { get; set; }
}

然后我的逻辑业务接受 IUserDbContext 而不是 SampleDataContext

public static List<SampleUser> ListUsers(IUserDbContext db)
{
    return db.UserSet.All().ToList();
}

通过这种方法,我可以拥有许多具有自由结构的数据库并实现 IUserDbContext ,因此我的使用业务逻辑可以与任何这些数据上下文一起使用。

例如,我想要一个与当前用户业务逻辑兼容的新数据上下文库,并且在User实体上还有额外的字段。我喜欢以下内容:

public class MyDataContext : DbContext, IUserDbContext
{
    public DbSet<MyUser> Users { get; set; }


    private IDbSet<SampleUser, int> _userSet;
    public IDbSet<SampleUser, int> UserSet
        {
            get { return _userSet ?? (_userSet = new UserInterface() { Db = this }); }
            set { _userSet = value; }
        }
    public class UserInterface : IDbSet<SampleUser, int>
        {
            public MyDataContext Db { get; set; }

            public SampleUser Add() => Db.Users.Add(new MyUser());

            public IQueryable<SampleUser> All() => Db.Users;

            public SampleUser Get(int id) => Db.Users.Find(id);

            public void Delete(int id) => Db.Users.Remove(Db.Users.Find(id)??new MyUser());
        }
}


[Table("Users")]
public class MyUser : SampleUser
{
    public string Color { get; set; }

    public override string ToString()
    {
        return base.ToString() + $"/ color : {Color}";
    }
}

我希望这很有用,或者给你一个好主意。

答案 2 :(得分:0)

当前,在新的EF中,设计非常狡猾。他们使用区分字段。 如果您希望使用从基表继承的单独表的旧方法,则 您正在寻找每种类型的表格实现。

这里是有关如何实现该目标的教程: https://weblogs.thinktecture.com/pawel/2018/05/entity-framework-core-inheritance-table-per-type-tpt-is-not-supported-is-it-part-2-database-first.html

答案 3 :(得分:-1)

EF可以自动映射这个继承,它很容易并且对性能有好处,你不必担心创建这个bool属性。

  

整个类层次结构可以映射到单个表。此表包含层次结构中所有类的所有属性的列。由特定行表示的具体子类由类型鉴别器列的值标识。您无需在Code First中执行任何特殊操作即可启用TPH。它是默认的继承映射策略:

enter image description here

enter image description here

更多信息 http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph