删除家长带着孩子在一对多的关系 [英] Delete parent with children in one to many relationship
问题描述
我有实体框架5.0êSQL服务器CE 4.0。
I have a .NET4.0 application with Entity Framework 5.0 e Sql Server CE 4.0.
我有两个实体,一个一对多(父/子)的关系。我已经将其配置为级联删除父去除,但由于某些原因,它似乎并没有工作。
I have two entities with a one to many (parent/child) relationship. I've configured it to cascade delete on parent removal, but for some reason it doesn't seem to work.
下面是我的实体的一个简化版本:
Here is a simplified version of my entities:
public class Account
{
public int AccountKey { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
internal class AccountMap : EntityTypeConfiguration<Account>
{
public AccountMap()
{
this.HasKey(e => e.AccountKey);
this.Property(e => e.AccountKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(e => e.Name).IsRequired();
}
}
public class User
{
public int UserKey { get; set; }
public string Name { get; set; }
public Account Account { get; set; }
public int AccountKey { get; set; }
}
internal class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
this.HasKey(e => e.UserKey);
this.Property(e => e.UserKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(e => e.Name).IsRequired();
this.HasRequired(e => e.Account)
.WithMany(e => e.Users)
.HasForeignKey(e => e.AccountKey);
}
}
public class TestContext : DbContext
{
public TestContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Conventions.Remove<StoreGeneratedIdentityKeyConvention>();
modelBuilder.LoadConfigurations();
}
}
连接字符串:
The connection string:
<connectionStrings>
<add name="TestContext" connectionString="Data Source=|DataDirectory|\TestDb.sdf;" providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>
和我的应用程序的工作流程的简化版本:
And a simplified version of my app's workflow:
static void Main(string[] args)
{
try
{
Database.SetInitializer(new DropCreateDatabaseAlways<TestContext>());
using (var context = new TestContext())
context.Database.Initialize(false);
Account account = null;
using (var context = new TestContext())
{
var account1 = new Account() { Name = "Account1^" };
var user1 = new User() { Name = "User1", Account = account1 };
context.Accounts.Add(account1);
context.Users.Add(user1);
context.SaveChanges();
account = account1;
}
using (var context = new TestContext())
{
context.Entry(account).State = EntityState.Deleted;
context.SaveChanges();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress any key to exit...");
Console.ReadLine();
}
当我尝试删除父实体,它抛出:
When I try to delete the parent entity, it throws:
的关系不能被改变,因为一个或多个的 外键的属性是不可为空。当进行更改时到 关系,相关的外键属性设置为空值。 如果外键不支持空值,一种新的关系 必须定义,外键属性必须指派另一 非空值,或者不相关的对象必须被删除。
The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
我相信我的关系配置是OK(跟着文档) 。我也搜索<一个href="http://stackoverflow.com/questions/12742473/most-efficiently-handling-create-update-delete-with-entity-framework-$c$c-firs">guidelines在删除分离的实体的。
I believe my relationship configuration is ok (followed the documentation). I also searched for guidelines on deleting detached entities.
我实在不明白为什么删除将无法正常工作。我想,以避免加载所有的孩子,删除它们逐个与他们删除父,因为必须有比这更好的解决方案。
I really cannot understand why that delete won't work. I want to avoid loading all the children, deleting them one by one and them deleting the parent, because there must be a better solution than that.
推荐答案
实体的状态设置为删除
并调用 DbSet&LT; T&GT;卸下摆臂
此实体是不一样的。
Setting the state of an entity to Deleted
and calling DbSet<T>.Remove
for this entity are not the same.
不同的是,设置国家只改变了根实体(传递到 context.Entry
的一个)删除<状态/ code>但相关的实体不在状态,而
删除
这是否如果关系配置了级联删除。
The difference is that setting the state only changes the state of the root entity (the one you pass into context.Entry
) to Deleted
but not the state of related entities while Remove
does this if the relationship is configured with cascading delete.
如果你得到一个异常实际上依赖于被附加到上下文或没有子女(所有或部分)。这导致一个行为是有些难以遵循:
If you get an exception actually depends on the children (all or only a part) being attached to the context or not. This leads to a behaviour which is somewhat difficult to follow:
- 如果你调用
删除
你没有得到一个例外,不管孩子被加载与否。目前还是有区别的:- 如果孩子们贴在背景下,EF会生成一个
删除
语句为每个连接的孩子,然后父(因为删除
做了他们所有的标记为删除
) - 如果孩子们没有连接到上下文EF将只发送一个
删除
语句父到数据库,因为级联删除已启用该数据库将删除儿童为好。
- If you call
Remove
you don't get an exception, no matter if children are loaded or not. There is still a difference:- If the children are attached to the context, EF will generate a
DELETE
statement for every attached child, then for the parent (becauseRemove
did mark them all asDeleted
) - If the children are not attached to the context EF will only send a
DELETE
statement for the parent to the database and because cascading delete is enabled the database will delete the children as well.
- 如果孩子被连接到他们的国家将不会被设置为
删除
和EF会抱怨说,您要删除主(根实体)的范围内而不删除家属(孩子)或需要的关系,至少没有他们的外键设置为另一个根实体,是不是在删除
状态。这就是你有例外:帐户
是根,用户1
是一个依赖的帐户
并调用context.Entry(帐户).State = EntityState.Deleted;
也将附加用户1
状态不变
上下文(或更改检测的SaveChanges
将做到这一点,我不知道该邻接)。用户1
是account.Users
收集的一部分,因为关系修正它添加到集合中第一个方面,虽然你没T明确添加在你的code。 - 如果没有孩子被附加到上下文根的状态设置为
删除
将发送删除
语句到数据库中,并再次级联删除数据库将删除的儿童,以及。这工作也不例外。您的code会再努力,例如,如果您设置account.Users = NULL
的状态设置为删除之前
在第二个上下文或进入第二上下文之前。
- If children are attached to the context their state won't be set to
Deleted
and EF will complain that you are trying to delete a principal (the root entity) in a required relationship without deleting the dependents (the children) or at least without setting their foreign keys to another root entity that is not inDeleted
state. That's the exception you had:account
is the root anduser1
is a dependent ofaccount
and callingcontext.Entry(account).State = EntityState.Deleted;
will also attachuser1
in stateUnchanged
to the context (or change detection inSaveChanges
will do it, I'm not sure abut that).user1
is part of theaccount.Users
collection because relationship fixup added it to the collection in your first context although you didn't add it explicitly in your code. - If no children are attached to the context setting the state of the root to
Deleted
will send aDELETE
statement to the database and again cascading delete in the database will delete the children as well. This works without exception. Your code would then work for example if you setaccount.Users = null
before setting the state toDeleted
in the second context or before entering the second context.
在我看来,使用
删除
...In my opinion using
Remove
...using (var context = new TestContext()) { context.Accounts.Attach(account); context.Accounts.Remove(account); context.SaveChanges(); }
...显然是prefered方式,因为
的行为删除
更像是你所期望的用于级联所需关系删除(这是情况在你的模型)。关于其他实体的状态的操作状态变化的行为的依赖使得它以使用更加困难。我认为它是先进的使用率只有在特殊情况下。...is clearly the prefered way because the behaviour of
Remove
is much more like you would expect for a required relationship with cascading delete (which is the case in your model). The dependency of the behaviour of a manual state change on states of other entities makes it more difficult to use. I would consider it as advanced usage only for special cases.的差异并不广为人知或记录。我已经看到了它极少数的职位。唯一的一个,我能找到,现在又是<一个href="http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/5e53a469-1175-47d7-84bf-9a1a28dfd145/">this一个接Zeeshan Hirani 的。
The difference is not widely known or documented. I've seen very few posts about it. The only one that I could find right now again, is this one by Zeeshan Hirani.
这篇关于删除家长带着孩子在一对多的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- If the children are attached to the context, EF will generate a
- 如果孩子们贴在背景下,EF会生成一个