我觉得你可以去一个适合双方的关系方和面向对象方面是映射和对象模型到数据库中的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的属性/列在属性实体/表,然后你可以添加它,但你必须确保你将它设置为适当的值,因为它不需要映射。
一些数据库(Oracle)允许使用这样的密钥。你没有提到你正在使用哪个数据库。话虽如此,这种设计不适合标准的SQL DB或EF。我建议你以不同的方式解决你的问题。 – 2012-03-27 16:38:29
感谢Craig,我正在使用MS SQL Server。我可以用代码中的额外公共功能来管理这个问题。但它只会让我的团队成员感到困惑,而且会让事情变得更加复杂。我需要像(字符串)SomeProperty.Value或(int)SomeProperty.Value这样的使用方法。我不想执行额外的功能来获得物业的价值。 – oruchreis 2012-03-27 17:23:26