【发布时间】:2011-11-30 03:36:30
【问题描述】:
我正在尝试使用实体框架代码优先来实现 Web 应用程序。 我将在这样的示例中解释问题:
在我的数据库中有一系列产品。
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public virtual Type type { get; set; }
//..... Some other properties .....
}
每种产品都有自己的类型(食品、药品、多媒体等)。同样在我的数据库中将是这些类型的集合,它将由最终用户定义,并且将来可能会被修改/增加。
public class Type
{
public long Id { get; set; }
public string Name { get; set; }
//..... Some other properties .....
}
如您所知,每种产品都有自己的属性,具体取决于产品的类型。假设药物可能有
public bool PrescriptionOnly { get; set; }
和多媒体类型可能有
public Size DisplaySize { get; set; }
正如我之前提到的,类型将由最终用户定义,因此属性的数量和每个属性的数据类型现在是未定义的。此外,用户应该能够通过属性的特定值过滤产品(过滤模型取决于产品类型)。而这一切都应该使用 Code-First 模型来实现。
总而言之,我被卡住了,因为我不知道如何使用 EF Code-First 创建这种“动态”数据库结构。我想在 Type 类中创建一个字符串字段并保存 [key=value] 对,但这几乎不可能使用分页结果创建快速有效的填充。
对于我的问题的任何建议或解决方案,我将不胜感激。
最好的问候! 卢卡斯
我创建了这样的示例代码来可视化问题。数据库结构如下:
Category1 = "食物" [Property1 = "ForVegetarian", Property2 = "卡路里"] ## - Product1 = "披萨" ["false", "1500"] - Product1 = "沙拉" ["true", "300"]
Category2 = "多媒体" [Property1 = "DisplaySize", Property2 = "Warranty"] ## - Product1 = "PlasmaTV" ["55''", "36m"] - Product1 = "LCDMonitor" ["24''", "12m"]
public class Property
{
public long Id { get; set; }
public string Name { get; set; }
}
public class ProductCategory
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Property> Properties { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class PropertyValue
{
public long Id { get; set; }
public virtual Property Property { get; set; }
public string Value { get; set; }
}
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductCategory> Categories { get; set; }
public virtual ICollection<PropertyValue> Properties { get; set; }
}
public class TestDataBase : DbContext
{
public DbSet<ProductCategory> Categories { get; set; }
public DbSet<Property> Properties { get; set; }
public DbSet<PropertyValue> Values { get; set; }
public DbSet<Product> Products { get; set; }
public TestDataBase()
{ }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{ }
public static readonly TestDataBase context = new TestDataBase();
}
public class TestDataBaseInitializer : DropCreateDatabaseIfModelChanges<TestDataBase>
{
protected override void Seed(TestDataBase context)
{
ProductCategory cat1 = new ProductCategory
{
Name = "Food",
Properties = new List<Property>(),
Products = new List<Product>()
};
Property prop1_1 = new Property
{
Name = "ForVegetarian"
};
Property prop1_2 = new Property
{
Name = "Calories"
};
cat1.Properties.Add(prop1_1);
cat1.Properties.Add(prop1_2);
Product product1_1 = new Product
{
Name = "Pizza",
Categories = new List<ProductCategory>(),
Properties = new List<PropertyValue>()
};
product1_1.Categories.Add(cat1);
PropertyValue val1_1_1 = new PropertyValue
{
Property = prop1_1,
Value = "false"
};
PropertyValue val1_1_2 = new PropertyValue
{
Property = prop1_2,
Value = "1500"
};
product1_1.Properties.Add(val1_1_1);
product1_1.Properties.Add(val1_1_2);
cat1.Products.Add(product1_1);
Product product1_2 = new Product
{
Name = "Salad",
Categories = new List<ProductCategory>(),
Properties = new List<PropertyValue>()
};
product1_2.Categories.Add(cat1);
PropertyValue val1_2_1 = new PropertyValue
{
Property = prop1_1,
Value = "true"
};
PropertyValue val1_2_2 = new PropertyValue
{
Property = prop1_2,
Value = "300"
};
product1_2.Properties.Add(val1_2_1);
product1_2.Properties.Add(val1_2_2);
cat1.Products.Add(product1_2);
//--------------------------------------------------------------------------------
ProductCategory cat2 = new ProductCategory
{
Name = "Multimedia",
Properties = new List<Property>(),
Products = new List<Product>()
};
Property prop2_1 = new Property
{
Name = "DisplaySize"
};
Property prop2_2 = new Property
{
Name = "Warranty"
};
cat2.Properties.Add(prop2_1);
cat2.Properties.Add(prop2_2);
Product product2_1 = new Product
{
Name = "PlasmaTV",
Categories = new List<ProductCategory>(),
Properties = new List<PropertyValue>()
};
product2_1.Categories.Add(cat2);
PropertyValue val2_1_1 = new PropertyValue
{
Property = prop2_1,
Value = "55''"
};
PropertyValue val2_1_2 = new PropertyValue
{
Property = prop2_2,
Value = "36m"
};
product2_1.Properties.Add(val2_1_1);
product2_1.Properties.Add(val2_1_2);
cat2.Products.Add(product2_1);
Product product2_2 = new Product
{
Name = "LCDMonitor",
Categories = new List<ProductCategory>(),
Properties = new List<PropertyValue>()
};
product2_2.Categories.Add(cat2);
PropertyValue val2_2_1 = new PropertyValue
{
Property = prop2_1,
Value = "24''"
};
PropertyValue val2_2_2 = new PropertyValue
{
Property = prop2_2,
Value = "12m"
};
product2_2.Properties.Add(val2_2_1);
product2_2.Properties.Add(val2_2_2);
cat2.Products.Add(product2_2);
context.Properties.Add(prop1_1);
context.Properties.Add(prop1_2);
context.Properties.Add(prop2_1);
context.Properties.Add(prop2_2);
context.Values.Add(val1_1_1);
context.Values.Add(val1_1_2);
context.Values.Add(val1_2_1);
context.Values.Add(val1_2_2);
context.Values.Add(val2_1_1);
context.Values.Add(val2_1_2);
context.Values.Add(val2_2_1);
context.Values.Add(val2_2_2);
context.Categories.Add(cat1);
context.Categories.Add(cat2);
context.SaveChanges();
}
}
现在假设我属于 多媒体 类别:
var category = (from c in TestDataBase.context.Categories
where c.Name == "Multimedia"
select c).First();
我知道这个类别有两个属性:DisplaySize和Warranty 假设我想选择 多媒体 类别中的所有产品(如 IEnumerable)(请注意,产品可能在多个类别中)。
var categoryProducts = (from c in TestDataBase.context.Categories
where c.Name == "Multimedia"
select c.Products).First();
此外,我必须通过 DisplaySize 属性过滤这组产品。我想选择以下产品:
- 具有 NOT NULL DisplaySize 属性
- 显示尺寸 == 55''
这里有一个问题:我不知道如何在 LINQ to Entity 中指定选择此类产品,因为每个产品都有自己的 PropertyValue 对象集合 - 而不仅仅是一个 PropertyValue .
谁能帮帮我。提前谢谢!
【问题讨论】:
-
我不明白你的问题?您的意思是 ORM 或对象序列化之类的东西?
-
不,我的意思是数据库设计(ADO.NET、EF、Code-First)以轻松实现我所描述的功能。
标签: entity-framework database-design entity-framework-4.1 ef-code-first database-schema