Как создать «динамическую» структуру базы данных (EF Code-First)

#entity-framework #database-design #entity-framework-4.1 #ef-code-first #database-schema

#entity-framework #database-design #entity-framework-4.1 #ef-code-first #база данных-схема

Вопрос:

Я пытаюсь реализовать веб-приложение, используя сначала код Entity Framework. Я объясню проблему на таком примере:

В моей базе данных есть коллекция продуктов.

 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. Я думал о создании одного строкового поля внутри класса типов и сохранении пар [ключ = значение], но это сделает практически невозможным быстрое и эффективное заполнение результатами подкачки.

Я буду благодарен за любое предложение или решение моей проблемы.

С наилучшими пожеланиями! Lukasz


Я создал такой пример кода, чтобы визуализировать проблему. Структура базы данных выглядит следующим образом:

Категория1 = «Еда» [Свойство1 = «Для вегетарианцев», Свойство2 = «Калории»] ## — Продукт1 = «Пицца» [«false», «1500»] — Продукт1 = «Салат» [«true», «300»]

Category2 = «Мультимедиа» [Свойство1 = «displaySize», Свойство2 = «Гарантия»] ## — 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
  • displaySize == 55″

И здесь возникает проблема: я не знаю, как указать в LINQ to Entity для выбора таких продуктов, потому что каждый продукт имеет свою собственную коллекцию объектов PropertyValue, А НЕ только одно PropertyValue .

Кто-нибудь может мне помочь. Заранее благодарю вас!

Комментарии:

1. я не понимаю вашего вопроса? вы имеете в виду что-то вроде ORM или сериализации объектов?

2. Нет, я имею в виду дизайн базы данных (ADO.NET , EF, Code-First) для легкого достижения функциональности, которую я описал.

Ответ №1:

ОК. Я думаю, что я решил свою проблему.

     var categoryProducts = (from p in category.Products
                                from c in p.Properties
                                where c.Property.Name == "DisplaySize" amp;amp;
                                      c.Value == "55''"
                            select p).ToList();
  

Вот хорошая статья о таком выборе:
http://weblogs.asp.net/salimfayad/archive/2008/07/09/linq-to-entities-join-queries.aspx