【问题标题】:Self referencing foreign key自引用外键
【发布时间】:2014-10-30 21:29:46
【问题描述】:

我正在使用 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 继承的配置。

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

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

我将为没有证据的记录添加一个“幽灵”用户以确定谁创建了记录,但这个幽灵用户基本上是由自己创建的。

当我尝试添加此幽灵用户时,我从 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.

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

自引用外键约束有问题吗?

【问题讨论】:

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


    【解决方案1】:

    您的 PK 是一个身份列,您正在使用自己设置 ghost 用户的 CreatedByUser 属性。这会导致鸡/蛋场景 - 您需要 User.Id 值作为 User.CreatedById 值将记录插入数据库表,但在插入记录之前您不知道 User.Id 是什么。

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

    否则,通过执行 SQL 语句创建您的 ghost 用户,允许您手动将 IdCreatedByUserId 字段设置为相同的值,然后将身份重新设置为 Id + 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-02-23
      • 2014-01-21
      • 2015-01-26
      • 1970-01-01
      • 2012-05-06
      • 2013-09-04
      • 2021-07-31
      • 1970-01-01
      相关资源
      最近更新 更多