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"); 
      }); 

所以,我的问题解决了。我想分享一下。