EF 4.1 RC:奇怪的级联删除

发布于 2024-10-24 21:17:17 字数 901 浏览 1 评论 0原文

我不得不承认,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 中想出了一些代码来禁用级联删除:

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

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

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

I have to admit, the features of EF 4.1 RC Codefirst, DataAnnotations and FluentAPI are still overwhelming to me. Sometimes I really don't know what I am doing ;-) Please see the following POCOs:

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; }
}

The general idea: Every country needs to have a currency. But a currency does not need to be assigned to a country at all.

If you let EF create the corresponding database, the relationship will be set to CASCADE DELETE by convention. In other words: if you delete a currency, the corresponding countries are deleted as well. But in my case this is not what I want.

I came up with some code in FluentAPI in order to disable CASCADE DELETE:

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

I thought this means: Every country requires a currency. And this currency might have zero, one or more countries assigned (optional). And whenever I delete a currency, the corresponding countries (if there are any) will NOT be cascade deleted.

Surprisingly the given approach will still cascade delete a country if I delete the corresponding currency. Can anybody tell me what I miss?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怼怹恏 2024-10-31 21:17:17

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

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

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();
    }          
  }
}

保存时您会收到错误,因为您删除了必需的外键。

Firstly you've specified the currency as a required field on country, so you can't delete a currency. You'll need to remove the [Required].

Secondly, your model builder need the following:

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

Thirdly, you need to explicitly remove the reference to the entity you are deleting from it's children:

 Currency c = context.Currencies.FirstOrDefault();

                c.Countries.Clear(); //these removes the link between child and parent

                context.Currencies.Remove(c);

                context.SaveChanges();

[EDIT]
Because I suspect there is something lost in translation find the complete code that demonstrates how no-cascading deletes would work.

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();
    }          
  }
}

You will get an error on saving, because your deleting something that is a required foreign key.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文