【问题标题】:EF 4.1 RC: Weird Cascade DeleteEF 4.1 RC:奇怪的级联删除
【发布时间】:2011-03-23 09:13:45
【问题描述】:

我不得不承认,EF 4.1 RC Codefirst、DataAnnotations 和 FluentAPI 的特性对我来说仍然是压倒性的。有时我真的不知道自己在做什么;-) 请查看以下 POCO:

public class Country
{
    [Key]
    public Guid ID { get; set; }

    [Required]
    public virtual Currency Currency { get; set; }
}

public class Currency
{
    [Key]
    public Guid ID { get; set; }

    public virtual ICollection<Country> Countries { get; set; }
}

总体思路:每个国家都需要有一种货币。但是货币根本不需要分配给一个国家/地区。

如果让 EF 创建对应的数据库,则按照约定将关系设置为 CASCADE DELETE。换句话说:如果您删除一种货币,相应的国家也会被删除。但就我而言,这 不是 我想要的。

我在 FluentAPI 中编写了一些代码来禁用 CASCADE DELETE:

modelBuilder.Entity<Country>()
            .HasRequired(cou => cou.Currency)
            .WithOptional()
            .WillCascadeOnDelete(false);

我认为这意味着:每个国家都需要一种货币。并且这种货币可能分配了零个、一个或多个国家/地区(可选)。并且每当我删除一种货币时,相应的国家(如果有的话)都不会被级联删除。

令人惊讶的是,如果我删除相应的货币,给定的方法仍然会级联删除一个国家/地区。谁能告诉我我想念什么?

【问题讨论】:

    标签: ef-code-first cascading-deletes entity-framework-4.1 fluent-interface


    【解决方案1】:

    首先,您已将货币指定为国家/地区的必填字段,因此您无法删除货币。您需要删除 [必需]。

    其次,您的模型构建器需要以下内容:

    modelBuilder.Entity<Country>()
                .HasRequired(cou => cou.Currency) //note optional, not required
                .WithMany(c=>c.Countries)         //define the relationship
                .WillCascadeOnDelete(false);
    

    第三,您需要从其子项中显式删除对要删除的实体的引用:

     Currency c = context.Currencies.FirstOrDefault();
    
                    c.Countries.Clear(); //these removes the link between child and parent
    
                    context.Currencies.Remove(c);
    
                    context.SaveChanges();
    

    [编辑] 因为我怀疑翻译中丢失了一些东西,所以找到完整的代码来演示非级联删除如何工作。

    public class Country{
      [Key]
      public Guid ID { get; set; }
    
      public virtual Currency Currency { get; set; }
    }
    
    public class Currency{
      [Key]
      public Guid ID { get; set; }
    
      public virtual ICollection<Country> Countries { get; set; }
    }
    
    
    public class MyContext : DbContext{
      public DbSet<Currency> Currencies { get; set; }
      public DbSet<Country> Countries { get; set; }
    
      protected override void OnModelCreating(DbModelBuilder modelBuilder){
        modelBuilder.Entity<Country>()
         .HasRequired(country => country.Currency)
         .WithMany(currency => currency.Countries)
         .WillCascadeOnDelete(false);
      }
    }
    
    class Program{
      static void Main(string[] args){
        Database.DefaultConnectionFactory = new   SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    
        Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
    
        using (MyContext context1 = new MyContext()){
          Currency c = new Currency{ID = Guid.NewGuid()};
    
          context1.Currencies.Add(c);
    
          c.Countries = new List<Country>();
    
          c.Countries.Add(new Country{ID = Guid.NewGuid()});
    
          context1.SaveChanges();
       }
    
       using (MyContext context2 = new MyContext()){
         Currency c = context2.Currencies.FirstOrDefault();
    
         context2.Currencies.Remove(c);
    
         //throws exception due to foreign key constraint
         //The primary key value cannot be deleted 
         //because references to this key still exist.   
         //[ Foreign key constraint name = Country_Currency ]
    
         context2.SaveChanges();
        }          
      }
    }
    

    保存时会出错,因为您删除的内容是必需的外键。

    【讨论】:

    • 感谢您的回复,Xhalent。不幸的是,我可能没有让自己足够清楚:在我的模型中,每个国家都需要一种货币。所以,我真的需要货币是[必需]。换句话说:如果至少分配了一个国家,我很高兴无法删除一种货币。但是,这并没有按预期工作。如果我删除相应的货币,级联删除仍然会删除一个国家。这并不好,我无法向自己解释它,因为我认为我通过流利的 API 语句关闭了 CASCADE DELETE。
    • 在这种情况下,保留 [Required],并将模型构建器修改为使用 .HasRequired 而不是 .Hasoptional,您将无法删除具有国家/地区的货币
    • @Xhalent:我应该在原始流利的 API 语句中使用 .HasRequired 而不是 .HasOptional 吗?你确定吗?现在我完全糊涂了。那是不是意味着每种货币都必须有一个国家?如果是这样,那将不符合我的业务规则,即货币可以分配一个国家(零、一、无限制)。
    • 不,我的意思是使用 MY Fluent 模型构建器,而不是 HasOptional 使用 .HasRequired。这意味着每个国家都必须有一种货币,但一种货币可能有很多国家(或没有)。
    • 您原始帖子中的流畅 API 没有我定义的 WithMany 规范 .HasMany(c=>c.Countries),所以看不出它们“或多或少完全是相同的”。当我对此进行测试时,它肯定会停止级联删除。在您上面的代码中,您有一个空的 HasMany() 规范,它没有任何意义——您需要说出您不想级联的关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    相关资源
    最近更新 更多