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

298 字
2 分钟
...阅读
...评论
Newegg

之前也遇到过类似的问题,属于 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),因为在这样多对多的绑定中,使用级联删除会报错。

评论区
Copyright © Bean Deng