簡體   English   中英

實體框架 5 - 派生類的基於枚舉的鑒別器

[英]Entity Framework 5 - Enum based Discriminator for derived classes

我有以下內容(為清楚起見而縮寫) - 一個枚舉,一個帶有該枚舉的基類,以及兩個將枚舉設置為特定值的派生類。

public enum MyEnum
{ 
    Value1, Value2
}

public class MyBaseClass
{ 
    public MyEnum { get; protected set; }
}

public class DerivedOne: MyBaseClass
{
    public DerivedOne { MyEnum = MyEnum.Value1; } 
}

public class DerivedTwo: MyBaseClass
{
    public DerivedTwo { MyEnum = MyEnum.Value2; }
}

我想要做的是讓實體框架 5 自動區分 DerivedOne 和 DerivedTwo,並使用基於 MyEnum 值的 discriminator 我應該能夠這樣做,因為按照慣例,每個 MyEnum == MyEnum.Value1 代表 DerivedOne,而 MyEnum == MyEnum.Value2 代表 DerivedTwo。

我在我的 DbContext 中試過這個:

public class MyDbContext : DbContext
{
    DbSet<MyBaseClass> MyBaseClass { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyBaseClass>()
                    .Map<DerivedOne>(m => m.Requires(x => x.MyEnum == MyEnum.Value1));

        base.OnModelCreating(modelBuilder);
    }
}

但是,這會引發以下 InvalidOperationException:

表達式 'x => (Convert(x.MyEnum) == 0)' 不是有效的屬性表達式。 表達式應該代表一個屬性 (...)

編輯:我相信我使用這個可以走得更遠:

modelBuilder.Entity<MyBaseClass>().Map<DerivedOne>(m => m.Requires("MyEnum")
                                  .HasValue((Int32)MyEnum.Value1));

現在我得到這個 EntityCommandCompilationException:

映射從第 (...) 行開始的片段問題 映射條件成員 'MyBaseClass.MyEnum' 的條件不是 'IsNull=False'。 刪除 MyBaseClass.MyEnum 上的條件或將其從映射中刪除。

關於我如何解決這個問題的任何提示? 謝謝!

據我所知,你不能那樣做。 做顯式Requires指定鑒別器只是給它一個name - 而不是將它連接到您的財產。

據我所知,這總是會導致您所描述的錯誤(稍后)。 如果你想指定鑒別器,它必須是“自動”的(至少我從來沒有設法這樣定義它)

但你真的不需要那個 “枚舉”和鑒別器built into您返回的類型中——基於鑒別器值,EF/CF 正在構建“Base”或“DerivedOne”或“DerivedTwo”。

因此,要實現您想要的功能,您可以執行以下操作...

public class MyBaseClass
{
    [NotMapped()]
    public virtual MyEnum MyEnum { get { return MyEnum.Base; } }
}

public class DerivedOne: MyBaseClass
{
    public string OneProp { get; set; }
    public override MyEnum MyEnum { get { return MyEnum.One; } }
}

public class DerivedTwo: MyBaseClass
{
    public string TwoProp { get; set; }
    public override MyEnum MyEnum { get { return MyEnum.Two; } }
}

或者只是使用is代替(如果它適合你)......

if (entity is MyBaseClass) // instead of enum  

或查詢...

.OfType<MyBaseClass>();

從 EF 6.1 開始,我實際上能夠使用枚舉作為鑒別器列,盡管有這個錯誤:

附加信息:“MyEnum”類型的值不能用作類型鑒別器值。 支持的類型包括字節、有符號字節、bool、int16、int32、int64 和 string。

我所要做的就是這樣:

public enum MyEnum
{ 
    Value1, Value2
}

public class MyBaseClass
{ 
    public MyEnum { get; protected set; }
}

public class DerivedOne: MyBaseClass
{
    public DerivedOne()
    {
        MyEnum = MyEnum.Value1;
    } 
}

public class DerivedTwo: MyBaseClass
{
    public DerivedTwo()
    {
        MyEnum = MyEnum.Value2;
    }
}

public class MyDbContext : DbContext
{
    DbSet<MyBaseClass> MyBaseClass { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations
            .Add(new DerivedOneConfiguration())
            .Add(new DerivedTwoConfiguration());
    }
}

public class DerivedOneConfiguration : EntityTypeConfiguration<DerivedOne>
{
    public DerivedOneConfiguration()
    {
        Map<DerivedOne>(_ => _.Requires("MyEnum").HasValue((int)MyEnum.Value1).IsRequired());
    }
}

public class DerivedTwoConfiguration : EntityTypeConfiguration<DerivedTwo>
{
    public DerivedTwoConfiguration()
    {
        Map<DerivedTwo>(_ => _.Requires("MyEnum").HasValue((int)MyEnum.Value2).IsRequired());
    }
}

所以秘密是使用(int)MyEnum.Value*而不是MyEnum.Value* ...

從 EF Core 開始,您可以直接在 Fluent API 上使用枚舉。 如果您的 MyBaseClass 未映射,您可以刪除描述基本鑒別器的第一行HasValue

modelBuilder.Entity<MyBaseClass>()
    .HasDiscriminator<MyEnum>("MyEnum")
    .HasValue<MyBaseClass>(MyEnum.Value0)
    .HasValue<DerivedOne>(MyEnum.Value1)
    .HasValue<DerivedTwo>(MyEnum.Value2);

基於@rsenna 的回答,但更新了基於 Microsofts Fluent Api 原始文檔的映射。

https://msdn.microsoft.com/en-us/library/jj591617%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396

public enum MyEnum
{ 
    Value1, Value2
}

public class MyBaseClass
{ 
    [NotMapped]
    public MyEnum MyEnum { get; protected set; }
}

public class DerivedOne: MyBaseClass
{
    public DerivedOne()
    {
        MyEnum = MyEnum.Value1;
    } 
}

public class DerivedTwo: MyBaseClass
{
    public DerivedTwo()
    {
        MyEnum = MyEnum.Value2;
    }
}

public class MyDbContext : DbContext
{
    DbSet<MyBaseClass> MyBaseClass { get; set; }

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

        modelBuilder.Entity<MyBaseClass>()
            .Map<DerivedOne>(x => x.Requires("MyEnum").HasValue((int)MyEnum.Value1))
            .Map<DerivedTwo>(x => x.Requires("MyEnum").HasValue((int)MyEnum.Value2));
    }
}

我想知道向MyEnum添加第三個值來表示基類是否會有所幫助。 然后在構造函數中將MyBaseClass.MyEnum設置MyBaseClass.MyEnum特定的“默認” enum值。

我認為 Table-per-heirarchy 結構需要每個類型都必須有一個有效的鑒別器。 因此,您有 3 種類型:

  1. MyBaseClass
  2. DerivedOne
  3. DerivedTwo

即使您的應用程序永遠不會以其基本形式使用 MyBaseClass,EF 仍然需要一個有效的鑒別器映射。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM