自引用外键

时间:2014-10-30 21:29:47

标签: c# sql sql-server entity-framework inheritance

我正在使用Entity Framework Code-First来重建曾经从Access数据库运行的应用程序。其中一个要求是新数据模式应该是可审​​计的,即它应该显示谁创建了一个记录,谁更新了它以及何时更新等。

我已经创建了一个基本实体类,如下所示:

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

    public int CreatedByUserId { get; set; }
    public int? UpdatedByUserId { get; set; }

    public virtual User CreatedBy { get; set; }
    public virtual User UpdatedBy { get; set; }
}

然后我创建了一个继承自EntityTypeConfiguration的类,如下所示

public class BaseEntityTypeConfiguration<T> : EntityTypeConfiguration<T> where T : Entity
{
    Property(e => e.Id).HasColumnName(typeof(T).Name + "Id");

    HasRequired(e => e.CreatedBy).WithMany().HasForeignKey(e => e.CreatedById);
    HasOptional(e => e.UpdatedBy).WithMany().HasForeignKey(e => e.UpdatedById);
}

现在,我创建了从BaseEntityTypeConfiguration继承的继承自我的Entity类的其余业务类的配置。

当我尝试让我的User类从实体继承时出现问题,如下所示:

public class User : Entity
{
    public string Username { get; set; }
    // etc
}

我要添加一个&#34;幽灵&#34;用户的记录,其中的证据不是确定谁创建了记录,但这个鬼用户基本上是自己创建的。

当我尝试添加此ghost用户时,我从Entity Framework收到以下错误:

Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements or store-generated values.

我的域名模型中可能存在可能导致此错误的问题,但我的理论是,这个用户试图在此实例中创建自己。

自引用外键约束是否有问题?

1 个答案:

答案 0 :(得分:1)

您的PK是一个标识列,您正在设置ghost用户的CreatedByUser属性。这会导致鸡/蛋情景 - 您需要User.Id值作为User.CreatedById值才能将记录插入到数据库表中,但您不知道User.Id之前是什么1记录被插入。

如果您可以确定身份的种子值(EF似乎默认为CreatedByUserId),则可以将CreatedByUser属性设置为该值而不是Id

否则,通过执行SQL语句创建ghost用户,允许您手动将CreatedByUserIdId + 1字段设置为相同的值,然后将标识重新设置为public class UserWithCreatedBy { [Key] [DatabaseGenerated( DatabaseGeneratedOption.Identity )] public int Id { get; set; } public int CreatedById { get; set; } [ForeignKey( "CreatedById" )] public UserWithCreatedBy CreatedBy { get; set; } } static void Main( string[] args ) { using( var db = new TestContext() ) { var u = new UserWithCreatedBy(); // doesn't work with identity //u.CreatedBy = u; // this will work as long as you know what the identity seed is // (whatever the next identity value will be) u.CreatedById = 1; db.UsersWithCreatedBy.Add( u ); db.SaveChanges(); } }

前者的例子:

{{1}}