Необходимость навигационных свойств в моделях EF Core - PullRequest
0 голосов
/ 18 января 2019

Допустим, в нашем проекте мы используем C # и MsSQL, и у нас есть одна Products таблица с двумя столбцами (ID, Name)

Однажды мы решили сохранить информацию о продукте, заданную Company1, поэтому мы создали новую таблицу ProductInfoFromCompany1, поскольку в ней есть настраиваемые столбцы (ProductID, Price, CurrentScore)

На следующий день мы договорились с Company2, и теперь нам нужно также сохранить их данные. Итак, новая таблица -> ProductInfoFromCompany2 с разными столбцами (ProductID, Year, Rating)

В другой день мы договорились с Company3 и так далее ...

Итак, мы понятия не имеем, как будут выглядеть данные, предоставленные новыми компаниями. Вот почему нам нужно создать новую таблицу, потому что если мы используем одну таблицу Details, она будет слишком широкой с многочисленными пустыми столбцами

В Entity Framework Core у нас есть следующие модели:

public class ProductInfoFromCompany1
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public decimal Price { get; set; }
    public double CurrentScore { get; set; }

    public Product Product { get; set; }
}

public class ProductInfoFromCompany2
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public int Year { get; set; }
    public double Rating { get; set; }

    public Product Product { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }

    //Do we need these navigation properties in this class?
    //public ProductInfoFromCompany1 ProductInfoFromCompany1 { get; set; } 
    //public ProductInfoFromCompany2 ProductInfoFromCompany2 { get; set; }
}

Вы можете видеть, что мой вопрос комментируется в Product классе.

Нужно ли добавлять навигационные свойства в класс Product?

Причина, по которой я спрашиваю, состоит в том, что во всех прочитанных мной книгах или документах люди используют свойство навигации, но в этом случае оно нарушает принцип открытого-закрытого доступа, потому что всякий раз, когда мы добавляем новую компанию, нам необходимо изменить Product класс тоже.

P.S. если мы хотим запросить данные ProductInfoFromCompany1 и у нас есть продукт Id, мы можем просто начать запрашивать с ProductInfoFromCompany1, например,

var info = _db.ProductInfoesFromCompany1.Where(c=>c.ProductId == productId);

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Нужно ли добавлять свойства навигации в класс Product?

Вы единственный, кто может ответить на вопрос, если вам нужно что-то или нет.

Если вопрос требует ли EF Core навигационных свойств, ответ - нет.Ссылка: Отношения - Одно свойство навигации Тема документации EF Core:

Включение только одного свойства навигации (без обратной навигации и без свойства внешнего ключа) достаточно для определения отношенияпо соглашению.

На самом деле EF Core свободно использует API и свойства теней позволяют определять отношения без какой-либо навигации или свойства FK.Насколько это было бы полезно - другая история.Основной момент (который я сейчас читаю) заключается в том, что ни один из них не является обязательным.

Конечно, отсутствие свойства навигации накладывает некоторые ограничения на тип запросов LINQ, которые вы можете создавать - как выПри этом вы не можете запустить запрос с Product и применить фильтр к ассоциированному ProductInfoFromCompany1, или хотите / явно / лениво загрузить его.

Но если вам все это не нужно, например, как вы сказали, вы можете строить свои запросы, начиная с ProductInfoFromCompany1, тогда исключение свойства навигации в Product вполне подойдет.

0 голосов
/ 18 января 2019

Как я уже упоминал в своем комментарии, для достижения того, чего вы хотите, требуется изменение дизайна. Вот мое предложение:

Поскольку ваша проблема связана со структурой таблицы продуктов, поскольку вы не знаете, что каждая компания хочет сохранить в качестве информации для своего продукта, вы можете сделать это следующим образом: (я объясню позже).

 public class Company
    {
        [Key]
        public int Id { get; set; }

        [Display(Name = "Name")]
        [Required]
        public string Name { get; set; }

        [Display(Name = "Description")]
        public string Description { get; set; }

        [Required]
        [Display(Name = "Created date")]
        [DataType(DataType.DateTime)]
        public DateTime CreatedDate { get; set; }

        public virtual ICollection<Product> Prodcuts { get; set; }

    }

    public class Product
    {
        [Key]
        public int Id { get; set; }

        [Display(Name="Name")]
        [Required]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Created date")]
        [DataType(DataType.DateTime)]
        public DateTime CreatedDate { get; set; }

        [Required]
        [ForeignKey("Company")]
        [Display(Name = "Company")]
        public int CompanyID { get; set; }
        public virtual Company Company { get; set; }

        public virtual ICollection<ProductField> Fields { get; set; }

    }

    public class ProductField
    {
        [Key]
        public int Id { get; set; }

        [Display(Name = "Value")]
        [Required]
        public string Value { get; set; }

        [Required]
        [ForeignKey("Product")]
        [Display(Name = "Product")]
        public int ProductID { get; set; }
        public virtual Product Product { get; set; }

        [Required]
        [ForeignKey("Field")]
        [Display(Name = "Field")]
        public int FieldID { get; set; }
        public virtual Field Field { get; set; }

        [Required]
        [Display(Name = "Created date")]
        [DataType(DataType.DateTime)]
        public DateTime CreatedDate { get; set; }
    }


public class Field
    {
        [Key]
        public int ID { get; set; }

        [MaxLength(100)]
        [Index("ActiveAndUnique", 1, IsUnique = true)]
        [Required]
        [Display(Name = "Name")]
        public string Name { get; set; }

        [Display(Name = "Description")]
        public string Description { get; set; }

        [Required]
        [Display(Name = "Created date")]
        [DataType(DataType.DateTime)]
        public DateTime CreatedDate { get; set; }
    }

Пояснение к коду:

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

Компания: Я начал с создания таблицы компании со свойством навигации, которое будет лениво загружать все связанные с ним продукты (если ленивая загрузка включена). Затем в таблицу продуктов я добавил FK для ссылки на компанию.

Поле: Поскольку вы упомянули, что не знаете, что компания будет иметь в качестве информации о продукте, вы можете создать новое поле и связать его с продуктом, используя таблицу ProductField.

ProductField: Эта таблица будет действовать как «многие ко многим» между вашим продуктом и полем, в результате вы можете добавить столько полей в новый продукт без необходимости изменять структуру таблицы вашего продукта или создавать новую. Вы также можете повторно использовать это поле, если оно требуется компании № 3.

ИСПОЛЬЗОВАНИЕ:

Учитывая, что у нас есть компания с именем MyCompany . У MyCompany есть продукт под названием Car, и информация, которую необходимо добавить в автомобиль, - это Make, and Color. Мы создаем два новых поля с именами Make и Color, затем в таблицу ProductField добавляем две новые записи: Первый будет иметь: Идентификатор поля «Марка», значение «BMW» и ссылка на товар с идентификатором «Автомобиль». Мы делаем то же самое для цвета, ссылаясь на поле «Цвет» и продукт «Автомобиль».

Запросы: Теперь запросить проще, чем иметь таблицу для каждой информации о продукте компании.

Пример:

var myProducts = _db.Products.Where(p=>p.CompanyID== "1").Include(p=>p.Fields).Tolist()

Опять же, это мое мнение. Надеюсь, это поможет.

...