2012-05-14 29 views
4

经过几个小时的反复试验,我到达了这个thread,它解释了如何建立一个一对多,使用相同的两种类型的多对多关系和一对一关系。实体框架5.0b2代码优先:一对多和一对一的同一个表,带级联删除

但是,我不能让这个与级联工作删除:

抛出该异常:“无法确定相关 操作的有效顺序依赖可能存在由于外键约束, 模型的要求,或商店生成的值“。 (System.Data.UpdateException)异常消息=“无法确定 依赖操作的有效排序。由于外键约束,模型要求或存储生成的 值的 可能存在相关性。”,Exception Type =“System .Data.UpdateException“

这只会发生,如果我没有取消设置1:1关系(见下面的代码),我认为是有道理的,因为它会创建一个无效的引用。我只是想知道是否有更好的方式来表达这一点。

示例代码:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Database.SetInitializer(new DropCreateDatabaseAlways<Context>()); 

     using (var ctx = new Context()) 
     { 
      var user = new User(); 

      ctx.Users.Add(user); 
      ctx.SaveChanges(); 

      var source = new PaymentSource(); 
      user.PaymentSources = new Collection<PaymentSource>(); 
      user.PaymentSources.Add(source); 
      user.DefaultPaymentSource = source; 
      ctx.SaveChanges(); 

      // if I don't do this, I get ordering exception 
      user.DefaultPaymentSource = null; 
      ctx.SaveChanges(); 

      ctx.Users.Remove(user); 
      ctx.SaveChanges(); 

      Assert.Equal(0, ctx.Users.Count()); 
      Assert.Equal(0, ctx.PaymentSources.Count()); 
     } 
    } 
} 

public class User 
{ 
    public int Id { get; set; } 

    public virtual ICollection<PaymentSource> PaymentSources { get; set; } 
    public virtual PaymentSource DefaultPaymentSource { get; set; } 
    public int? DefaultPaymentSourceId { get; set; } 
} 

public class PaymentSource 
{ 
    public int Id { get; set; } 
    public virtual User User { get; set; } 
    public int UserId { get; set; } 
} 

public class Context : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<PaymentSource> PaymentSources { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Entity<User>() 
      .HasOptional(u => u.DefaultPaymentSource) 
      .WithMany() 
      .HasForeignKey(u => u.DefaultPaymentSourceId) 
      .WillCascadeOnDelete(false); 

     modelBuilder.Entity<PaymentSource>() 
      .HasRequired(p => p.User) 
      .WithMany(p => p.PaymentSources) 
      .HasForeignKey(p => p.UserId) 
      .WillCascadeOnDelete(); 
    } 
} 
+0

你能解释一下两个需要1-1和1- *关系的表吗?更具体一点:它是否假定给出树结构的抽象? –

+0

我认为模型是不言自明的,但我想不是。那么,'User'有N个'PaymentSource's(1:N),并且还保留默认值(1:1,0:1是严格的)。 – georgiosd

回答

2

我列出的其他选项来描述你的抽象:

A.

如何使用3台这样的:

user 1-* paymentSource 
user 1-0..1 DefaultPaymentSource 
DefaultPaymentSource 0..1-1 PaymentSource 

或者这个:

B.

user 1-* paymentSource 
user 1-0..1 DefaultPaymentSource 
DefaultPaymentSource --derive from--> PaymentSource 

或本:

C.

user 1-* paymentSource 
PaymentSource has addtional boolean field for "IsDefault" 

我投票选择B中最好的一个。

我确信有两个关系从同一个源表到同一个目标表是不会是一个好主意..它可能违反了关于数据库最佳实践的一些规则或模式。

+0

我反对B和C,因为它们很容易产生问题如果你没有在代码中只保留*一个*'DefaultPaymentSource'。换句话说,一个完美的模型可以确保:a)任何时候只有一个'PaymentSource'可以被默认,而不涉及逻辑,b)如果默认被删除不会产生问题(我的模型不会这样做)。 A)如何翻译代码?不知道我完全理解它。 – georgiosd

+0

嗯..烨 - C会有你描述的问题..但A或B可以使用没有多个默认的问题。但是,在这两种情况下,您都需要确保在删除源时不能将其用作默认值。关于代码,你只需创建一个删除方法,并在删除之前用你需要的条件填充它,但我明白 - 你在寻找更可级联的操作 - 你确定EF允许你设置这种方式吗? ? (imho)我不这么认为,但如果我错了,请让我知道。 –

+0

你可能是对的,它不允许它,我也不知道:)因此,这个问题!你能详细解释一下吗? B将有很多拳击/拆箱代码。 – georgiosd

相关问题