删除家长带着孩子在一对多的关系 [英] Delete parent with children in one to many relationship

查看:237
本文介绍了删除家长带着孩子在一对多的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有实体框架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 (because Remove did mark them all as Deleted)
      • 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 in Deleted state. That's the exception you had: account is the root and user1 is a dependent of account and calling context.Entry(account).State = EntityState.Deleted; will also attach user1 in state Unchanged to the context (or change detection in SaveChanges will do it, I'm not sure abut that). user1 is part of the account.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 a DELETE 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 set account.Users = null before setting the state to Deleted 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆