Entity Framework Code First 两个字段关联到同一张表

之前也遇到过类似的问题,属于Code First中稍微复杂点的关系处理,现将解决方法记录下来。

场景:

某网上书城欲推出书券功能,书券购买之后,会有一个唯一的Id,可用来直接兑换某本书。书券可以自己兑换,也可以将ID送给朋友来兑换。现在我们需要将书券的购买者和兑换者都记录下来。

类的设计和注意事项:

public class BookCoupon
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    [Index("BookCouponIdIndex")]
    public Guid BookCouponId { get; set; }

    [Index("BookIdIndex")]
    public int BookId { get; set; }

    [ForeignKey("BookId")]
    public virtual Book Book { get; set; }

    [Index("BuyUserIdIndex")]
    public string BuyUserId { get; set; }

    [ForeignKey("BuyUserId")]
    public virtual User BuyUser { get; set; }

    [Index("RedeemUserIdIndex")]
    public string RedeemUserId { get; set; }

    [ForeignKey("RedeemUserId")]
    public virtual User RedeemUser { get; set; }

    public DateTime BuyTime { get; set; }

    public DateTime RedeemTime { get; set; }
}
public class User
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    [Index("UserIdIndex")]
    public Guid UserId { get; set; }

    public string UserName { get; set; }

    public virtual ICollection<BookCoupon> BuyCoupons { get; set; }

    public virtual ICollection<BookCoupon> RedeemCoupons { get; set; }

    ......
}

另外,在DbContext中需要override OnModelCreating方法:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<ApplicationUser>().HasMany(u => u.BuyCoupons).WithRequired(n => n.BuyUser).WillCascadeOnDelete(false);
    modelBuilder.Entity<ApplicationUser>().HasMany(u => u.RedeemCoupons).WithRequired(n => n.RedeemUser).WillCascadeOnDelete(false);
}

注意最后的.WillCascadeOnDelete(false),因为在这样多对多的绑定中,使用级联删除会报错。

by HADB @ Newegg