[英]EF - Remove a relationship from parent entity
假设我的模型中有两个类: Product
和Category
。
public class Product
{
public Product() {
this.Categories = new HashSet<Category>();
}
[...]
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
public Category() {
this.Products = new HashSet<Product>();
}
[...]
public virtual ICollection<Product> Products { get; set; }
}
产品具有许多类别,并且类别适用于许多产品。 为了对此关系建模,我在OnModelCreating
方法中具有以下代码:
modelBuilder.Entity<Product>()
.HasMany( p => p.Categories )
.WithMany( p => p.Products )
.Map( m => {
m.MapLeftKey( "ProductID" );
m.MapRightKey( "CategoryID" );
m.ToTable( "CategoriesPerProduct" );
} );
modelBuilder.Entity<Category>()
.HasMany( p => p.Products )
.WithMany( p => p.Categories )
.Map( m => {
m.MapLeftKey( "CategoryID" );
m.MapRightKey( "ProductID" );
m.ToTable( "CategoriesPerProduct" );
} );
这将创建一个新表CategoriesPerProduct
,该表将MN关系分为两个1-N关系,这很适合我的需求。
我现在需要更新与产品相关的类别,并且为了简化我的代码,我确实决定删除所有现有类别,然后像以下示例中一样重新添加新类别:
ICollection<Category> productCategories = product.Categories;
//First remove all existing categories
foreach ( var category in productCategories ) {
product.Categories.Remove( category );
}
// ..then add the new ones from input
foreach ( string categoryName in categories ) {
Category c = await _ctx.Categories.SingleOrDefaultAsync( p => p.Description == categoryName );
if ( c != null ) {
product.Categories.Add( pc );
}
else {
c = new ProductCategory() { Description = categoryName };
_ctx.Categories.Add( c );
await _ctx.SaveChangesAsync();
product.Categories.Add( c );
}
}
await _ctx.SaveChangesAsync();
不幸的是,当代码击中事务Commit()
方法时,出现以下错误:
由于一个或多个外键属性不可为空,因此无法更改该关系。 对关系进行更改时,相关的外键属性将设置为空值。 如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。
有人可以驱使我朝正确的方向解决这个错误吗?
再次编辑
我发生的另一件事是,您可能正在孤立关系的另一端-您要从产品中删除类别实体,但是您要从该类别中删除产品吗? 查看WillCascadeOnDelete( 一对一或一对一关系的实体框架(EF)代码第一个级联删除 )或尝试在查询中包括这些关系-而不是_ctx.Products.Where(...)
,请使用_ctx.Products.Include(p => p.Categories).Where(...)
让我们知道如何为您服务!
编辑
因此,根据洛伦佐的回应,我了解他正在尝试做的事情。 过去,这是困扰我(也许还有几个人)的事情。
您可能正在查看“级联删除”问题-选择选项3(现在已不是必需的选项...)。
主要问题是这个(据我所知,因为我们不知道CategoriesPerProduct的模式:我们的作案者):您正在将CategoriesPerProduct中的条目置于不可能的状态,该状态要求存在Category,但是Category已有效地设置为null。
因此,您有几种选择:
_ctx.Categories.Remove(category);
) ctx.Entry(category).State = EntityState.Deleted
) 我相信您会收到该异常,因为您要插入重复的项目。 重复的项目将转换为ProductCategoryID = 0
,因此您将获得异常。
在您的当前代码中进行以下更改:
ICollection<Category> productCategories = product.Categories;
//Make sure that you are iterating a copy of categories, using ToList()
//If you do not use ToList() you might get an exception saying that you changed the list you are iterating
foreach ( var category in productCategories.ToList()) {
product.Categories.Remove( category );
}
// ..then add the new ones from input
// ... but remember to add only the new ones
var currentCategories = productCategories.Select(i => i.Name);
// you could use another strategy here
foreach ( string categoryName in categories.Except(currentCategories)) {
Category c = await _ctx.Categories.SingleOrDefaultAsync( p => p.Description == categoryName );
if ( c != null ) {
product.Categories.Add( pc );
} else {
c = new ProductCategory() { Description = categoryName };
//_ctx.Categories.Add( c ); NOT NECESSARY - IT WILL BE AUTOMATICALLY INSERTED
//await _ctx.SaveChangesAsync(); NOT NECESSARY
product.Categories.Add( c );
}
}
未经测试的代码,但应该可以正常工作。
希望能帮助到你!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.