0

我想創建與實體框架的條件關聯。據我所知,我們不能創建條件外鍵,所以我無法在數據庫服務器級別解決這個問題。 我的表像:有條件的關聯實體框架

---Property--- 
int  id 
string Name 
int  TypeId  --> Condition on this. 
int  ValueId 

---ValueString--- 
int  id 
string Value 

---ValueInteger--- 
int  id 
int  Value 

---ValueBoolean--- 
int  id 
bool Value 

現在,在屬性表中的TYPEID字段包含值的類型。舉例來說,如果TYPEID == 0,然後VALUEID點的valueString表,如果TYPEID == 1,則值Id點的立即表等

我做了一些解決方法,但我還是堅持地方:

我有這樣的一個枚舉:

public enum PropertyType 
{ 
    String = 0, 
    Integer = 1, 
    Boolean = 2, 
    DateTime = 3, 
    List = 4 
} 

和我實現了一個局部類這樣的:

public partial class ProductProperty : EntityObject 
{ 
    public object Value 
    { 
     get 
     { 
      switch (Property.Type) 
      { 
       case PropertyType.String: 
        return ValueString.Where(w => w.id == this.ValueId).Select(s => s);//how to return? 
        break; 
       case PropertyType.Integer: 
        return ValueInteger.Where(w => w.id == this.ValueId).Select(s => s) //how to return? 
        break; 
       case PropertyType.Boolean: 
        return ValueBoolean.Where(w => w.id == this.ValueId).Select(s => s) //how to return? 
        break; 
       case PropertyType.DateTime: 
        return ValueDateTime.Where(w => w.id == this.ValueId).Select(s => s) //how to return? 
        break; 
       default: 
        return null; 
        break; 
      } 
     } 
     set 
     { 

     } 
    } 
} 

但我不知道如何在EntityObject內到達上下文對象,所以我無法到達Property EntityObject中的Value *表。

那麼,這種方法是真的還是我該怎麼做?如果它是真的,我怎麼能在EntityObject中獲得實體上下文對象?

編輯:如果你不建議這種方法,你會建議什麼?請與我們分享您的意見。我認爲,這種方法最好的選擇可能是這樣的:

---Property--- 
int  id 
string ValueString 
int  ValueInteger 
bool ValueBoolean 
etc... 

可是這樣一來,如果我想添加其他值類型,我將不得不改變表結構,我將有更新的實體和我的項目中的對象模型。我不能使用序列化對象,因爲我需要過濾數據的值。 編輯結束

+0

一些數據庫(Oracle)允許使用這樣的密鑰。你沒有提到你正在使用哪個數據庫。話雖如此,這種設計不適合標準的SQL DB或EF。我建議你以不同的方式解決你的問題。 – 2012-03-27 16:38:29

+0

感謝Craig,我正在使用MS SQL Server。我可以用代碼中的額外公共功能來管理這個問題。但它只會讓我的團隊成員感到困惑,而且會讓事情變得更加複雜。我需要像(字符串)SomeProperty.Value或(int)SomeProperty.Value這樣的使用方法。我不想執行額外的功能來獲得物業的價值。 – oruchreis 2012-03-27 17:23:26

回答

3

我覺得你可以去一個適合雙方的關係方和麪向對象方面是映射和對象模型到數據庫中的TPC抽象,它最接近已經非常接近你的桌子結構。爲了簡單起見,我將在EF 4.3.1中使用Code First進行展示。

讓我們定義一個簡單的對象模型,像這樣:

public class Property 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int ValueId { get; set; } 
    public virtual Value Value { get; set; } 
} 

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

public class ValueString : Value 
{ 
    public string Value { get; set; } 

    public override string ToString() 
    { 
     return "String value of " + Value; 
    } 
} 

public class ValueInteger : Value 
{ 
    public int Value { get; set; } 

    public override string ToString() 
    { 
     return "Integer value of " + Value; 
    } 
} 

public class ValueBoolean : Value 
{ 
    public bool Value { get; set; } 

    public override string ToString() 
    { 
     return "Boolean value of " + Value; 
    } 
} 

(我把一些的ToString方法只是爲了很容易地看到發生了什麼事情,當我們使用這些類。)

這可以使用TPC映射,使得每種類型都有自己的表:

public class PropertyAndValuesContext : DbContext 
{ 
    public DbSet<Property> Properties { get; set; } 
    public DbSet<Value> Values { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<ValueString>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ValueString"); 
      }); 

     modelBuilder.Entity<ValueInteger>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ValueInteger"); 
      }); 

     modelBuilder.Entity<ValueBoolean>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ValueBoolean"); 
      }); 
    } 
} 

所以,現在的表,我們有符合您在您的問題開始提供的佈局,除了TYPEID合作由於在此不需要,因此缺少列。

讓我們寫一個初始化函數和一個控制檯應用程序添加一些測試數據並顯示它:

public class TestInitializer : DropCreateDatabaseAlways<PropertyAndValuesContext> 
{ 
    protected override void Seed(PropertyAndValuesContext context) 
    { 
     new List<Property> 
     { 
      new Property { Name = "PropWithBool", Value = new ValueBoolean { Id = 1, Value = true } }, 
      new Property { Name = "PropWithString1", Value = new ValueString { Id = 2, Value = "Magic" } }, 
      new Property { Name = "PropWithString2", Value = new ValueString { Id = 3, Value = "Unicorn" } }, 
      new Property { Name = "PropWithInt1", Value = new ValueInteger { Id = 4, Value = 6 } }, 
      new Property { Name = "PropWithInt2", Value = new ValueInteger { Id = 5, Value = 7 } }, 
     }.ForEach(p => context.Properties.Add(p)); 
    } 
} 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     Database.SetInitializer(new TestInitializer()); 

     using (var context = new PropertyAndValuesContext()) 
     { 
      foreach (var property in context.Properties) 
      { 
       Console.WriteLine("{0} with {1}", property.Name, property.Value); 
      } 
     } 
    } 
} 

運行此打印出:

PropWithBool with Boolean value of True 
PropWithString1 with String value of Magic 
PropWithString2 with String value of Unicorn 
PropWithInt1 with Integer value of 6 
PropWithInt2 with Integer value of 7 

你可以看到,我們能夠輕鬆地添加不同類型的值,將它們存儲在適當的表中,然後再查詢這些值。

現在,也許你真的想要一個屬性的返回值作爲「對象」類型在你的例子中。好了,現在我們可以用一個簡單的抽象屬性做到這一點:

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

    public abstract object TheValue { get; set; } 
} 

public class ValueString : Value 
{ 
    public string Value { get; set; } 

    public override object TheValue 
    { 
     get { return Value; } 
     set { Value = (string)value; } 
    } 

    public override string ToString() 
    { 
     return "String value of " + Value; 
    } 
} 

public class ValueInteger : Value 
{ 
    public int Value { get; set; } 

    public override object TheValue 
    { 
     get { return Value; } 
     set { Value = (int)value; } 
    } 

    public override string ToString() 
    { 
     return "Integer value of " + Value; 
    } 
} 

public class ValueBoolean : Value 
{ 
    public bool Value { get; set; } 

    public override object TheValue 
    { 
     get { return Value; } 
     set { Value = (bool)value; } 
    } 

    public override string ToString() 
    { 
     return "Boolean value of " + Value; 
    } 
} 

你也可以想像這樣做,如果你想:

public class Property 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int ValueId { get; set; } 
    public virtual Value Value { get; set; } 

    public object TheValue 
    { 
     get { return Value.TheValue; } 
     set { Value.TheValue = value; } 
    } 
} 

最後,如果你真的需要typeid的屬性/列在屬性實體/表,然後你可以添加它,但你必須確保你將它設置爲適當的值,因爲它不需要映射。

+0

哇,很好的答案。我現在正在閱讀它,並且我試圖通過在我的項目中應用來理解它。成功後,我會接受這個答案。非常感謝。 – oruchreis 2012-03-28 20:23:25

0

Arthur的答案是答案,但我想分享我的結果。

首先,我試圖將屬性值實現爲泛型類型。然後我實現了每個ValueString,ValueInteger等。從這個泛型類型驅動的類。它的工作,但泛型類型的方法在使用中造成了很多鑄造。所以我堅持使用對象值。

這是屬性類,用於保存值和類型:

public class ProductProperty 
{ 
    public int ProductPropertyId { get; set; } 
    public Product Product { get; set; } 
    public int TypeId { get; set; } 
    public int ValueId { get; set; } 
    [ForeignKey("TypeId")] 
    public PropertyType Type { get; set; } 
    [ForeignKey("ValueId")] 
    public PropertyValue Value { get; set; } 
} 

這是屬性的類型。它具有簡單的類型,如字符串類型,它保存在數據庫中作爲字符串,int等。例如,此屬性類型可以是「Name」,其簡單類型可以是字符串,也可以是「Price」,其簡單類型是浮動。

public class PropertyType 
{ 
    public int PropertyTypeId { get; set; } 
    [MaxLength(150)] 
    public string Name { get; set; } 

    //For before EF 5, there is no enum support 
    [Column("SimpleType")] 
    public int InternalSimpleType { get; set; } 
    [NotMapped] 
    public SimpleType SimpleType 
    { 
     get { return (SimpleType)InternalSimpleType; } 
     set { InternalSimpleType = (int)value; } 
    } 

    public ICollection<ProductProperty> ProductProperties { get; set; } 
} 

public enum SimpleType : int 
{ 
    String = 1, 
    Integer = 2, 
    Float = 4, 
    Boolean = 8, 
    DateTime = 16, 
    List = 32 
} 

這是抽象基類值表亞瑟具有紅粉想法:

public abstract class PropertyValue 
{ 
    [Key] 
    public int PropertyValueId { get; set; } 
    [NotMapped] 
    public abstract object Value { get; set; } 
} 

這些值類/表:

public class PropertyValueString : PropertyValue 
{ 
    [Column("Value", TypeName="ntext")] 
    public string InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (string)InternalValue; 
     } 
     set 
     { 
      InternalValue = (string)value; 
     } 
    } 
} 

public class PropertyValueInteger : PropertyValue 
{ 
    [Column("Value")] 
    public int InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (int)InternalValue; 
     } 
     set 
     { 
      InternalValue = (int)value; 
     } 
    } 
} 

public class PropertyValueBoolean : PropertyValue 
{ 
    [Column("Value")] 
    public bool InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (bool)InternalValue; 
     } 
     set 
     { 
      InternalValue = (bool)value; 
     } 
    } 
} 

public class PropertyValueFloat : PropertyValue 
{ 
    [Column("Value")] 
    public float InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (float)InternalValue; 
     } 
     set 
     { 
      InternalValue = (float)value; 
     } 
    } 
} 

public class PropertyValueDateTime : PropertyValue 
{ 
    [Column("Value", TypeName = "datetime2")] 
    public DateTime InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (DateTime)InternalValue; 
     } 
     set 
     { 
      InternalValue = (DateTime)value; 
     } 
    } 
} 

這將在conext從DbContext驅動的類:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<PropertyValueString>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueString"); 
      }); 

     modelBuilder.Entity<PropertyValueInteger>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueInteger"); 
      }); 

     modelBuilder.Entity<PropertyValueBoolean>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueBoolean"); 
      }); 

     modelBuilder.Entity<PropertyValueFloat>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueFloat"); 
      }); 

     modelBuilder.Entity<PropertyValueDateTime>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueDateTime"); 
      }); 

所以,我的問題解決了。我想分享一下。