#c# #sql #entity-framework
#c# #sql #entity-framework
Вопрос:
Первый вопрос: Я столкнулся с проблемой, возникшей при попытке обновить базу данных:
УДАЛИТЬ ограничение ССЫЛКИ на конфликт инструкций «FK_Products_ProductTypes_ProductTypeId». Произошел конфликт в базе данных «GdmStore», таблица «dbo.Продукты», столбец ‘ProductTypeId’.
Второй вопрос: хороша ли моя объектная модель и взаимосвязь между объектами? Я должен создать базу данных, в которой у меня есть много разных «продуктов», и каждый «продукт» имеет свой собственный набор «параметров».
Мой DataContext:
public DataContext(DbContextOptions<DataContext> opts) : base(opts) { }
public DbSet<Product> Products { get; set; }
public DbSet<ProductType> ProductTypes { get; set; }
public DbSet<Parameter> Parameters { get; set; }
public DbSet<ProductParameter> ProductParameters { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasOne(c => c.ProductType)
.WithMany(e => e.Products)
.HasForeignKey(c => c.ProductTypeId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Parameter>()
.HasOne(Pr => Pr.ProductType)
.WithMany(Pt => Pt.Parameters)
.HasForeignKey(Pr => Pr.ProductTypeId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<ProductParameter>()
.HasOne<Product>(bc => bc.Product)
.WithMany(b => b.ProductParameters)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<ProductParameter>()
.HasOne<Parameter>(bc => bc.Parameter)
.WithMany(c => c.ProductParameters)
.OnDelete(DeleteBehavior.Restrict);
}
Это мои классы моделей:
public class Product //: BaseObject
{
public int ProductId { get; set; }
public string Number { get; set; }
public double Amount { get; set; }
public double PrimeCost { get; set; }
[ForeignKey("ProductTypeId")]
public int ProductTypeId { get; set; }
public ProductType ProductType { get; set; }
public int ProductParameterId { get; set; }
public ICollection<ProductParameter> ProductParameters { get; set; } = new List<ProductParameter>();
}
public class ProductType
{
public int ProductTypeId { get; set; }
public string TypeName { get; set; }
public ICollection<Product> Products { get; set; }
public ICollection<Parameter> Parameters { get; set; }
public ICollection<Parameter> Parameter { get; set; } = new List<Parameter>();
public ICollection<Product> Product { get; set; } = new List<Product>();
}
public class Parameter
{
public int ParameterId { get; set; }
public string Name { get; set; }
[ForeignKey("ProductTypeId")]
public int ProductTypeId { get; set; }
public ProductType ProductType { get; set; }
public ICollection<ProductParameter> ProductParameters { get; set; } = new List<ProductParameter>();
}
public class ProductParameter
{
public int ProductParameterId { get; set; }
public int ProductId { get; set; }
public int ParameterId { get; set; }
public Parameter Parameter { get; set; }
public Product Product { get; set; }
public string Value { get; set; }
}
Комментарии:
1. По одному четкому вопросу за раз.
2. Добавьте операцию, которую вы пытаетесь выполнить при получении исключения. Похоже, вы пытаетесь удалить тип продукта, в то время как продукт все еще ссылается на него. Исходя из общего первого наблюдения, я бы посоветовал удалить любые двунаправленные ссылки, которые вам не нужны. Например, действительно ли ProductType нужен список продуктов? (Вы всегда можете запросить это со стороны продукта с помощью
context.Products.Where(x => x.ProductType.ProductTypeId == productTypeId)
Ответ №1:
Судя по сообщению об ошибке, похоже, что вы пытаетесь удалить строку, от которой зависит другая строка.
Например, посмотрите на следующие таблицы:
--------------------------------------
PRODUCT_TYPE
--------------------------------------
(PK)PRODUCT_TYPE_ID | TYPE
--------------------------------------
1000 | Gimmick
1001 | Life Changing
--------------------------------------------------------
PRODUCT
--------------------------------------------------------
(PK)PRODUCT_ID | (FK)PRD_TYPE_ID | Name
--------------------------------------------------------
6521 | 1000 | Electric Pizza Cutter
6522 | 1001 | Bidet
Если бы я попытался запустить DELETE FROM PRODUCT_TYPE WHERE PRODUCT_TYPE_ID = 1000
, это завершилось бы неудачей. Почему? Что ж, если я удалю этот тип продукта, то у моего продукта Electric Pizza Cutter будет тип продукта mystery (больше нет 1000). Оно потеряно. Базы данных не похожи на Daddy Warbucks — они ненавидят сирот.
Если вам действительно нужно что-то удалить, вам нужно разобрать это с нижней части цепочки до самого верха. Но вы обнаружите, что очень редко что-либо когда-либо должно быть удалено в базе данных. Вместо удаления вы должны пометить его как неактивный. Мой предпочтительный маршрут использует конечную дату.
--------------------------------------------------
PRODUCT_TYPE
--------------------------------------------------
(PK)PRODUCT_TYPE_ID | TYPE | END_DATE
--------------------------------------------------
1000 | Gimmick | 3-25-2019
1001 | Life Changing | null
Точно так же мой тип продукта больше не используется, но старые вещи в DB все еще могут ссылаться на них, если это необходимо.