Sql server 2008 r2 实体框架代码第一个基类未映射到DB

Sql server 2008 r2 实体框架代码第一个基类未映射到DB,sql-server-2008-r2,ef-code-first,entity-framework-5,Sql Server 2008 R2,Ef Code First,Entity Framework 5,我首先在C#中使用实体框架代码,我有许多实体具有用于跟踪的相同列。我使用的列有Active、IsDeleted、CreatedBy、ModifiedBy、DateCreated和DateUpdated。将这些属性添加到我要跟踪的每个实体中似乎很乏味。我希望有一个基类,我的实体可以从中继承,比如下面的一个 public abstract class TrackableEntity { public bool Active { get; set; } public bool IsDe

我首先在C#中使用实体框架代码,我有许多实体具有用于跟踪的相同列。我使用的列有Active、IsDeleted、CreatedBy、ModifiedBy、DateCreated和DateUpdated。将这些属性添加到我要跟踪的每个实体中似乎很乏味。我希望有一个基类,我的实体可以从中继承,比如下面的一个

public abstract class TrackableEntity
{
    public bool Active { get; set; }
    public bool IsDeleted { get; set; }
    public virtual User CreatedBy { get; set; }
    public virtual User ModifiedBy { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
}
然后我可以从实体中的这个类继承这些属性,当数据库生成时,每个实体都会有这些列

public class UserProfile : TrackableEntity, IValidatableObject
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }

    public bool IsValid { get { return this.Validate(null).Count() == 0; } }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (String.IsNullOrEmpty(FirstName))
            yield return new ValidationResult("First name cannot be blank", new[] { "Username" });

        if (String.IsNullOrEmpty(LastName))
            yield return new ValidationResult("Last cannot be blank", new[] { "Password" });

        //Finish Validation Rules
    }
}

很可能是因为您的
User
类也是从
TrackableEntity
派生的,所以出现了此异常:

public class User : TrackableEntity
结果是
用户
实体现在包含两个继承属性

public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
根据约定,实体框架将假定两个属性之间的关系,即一个将这两个导航属性作为其两端的关系。因为导航属性是引用而不是集合,所以EF推断出一对一的关系。因为在模型中没有指定两个导航属性中哪一个具有关系的相关外键,所以EF无法确定关系的主体和依赖项-这会导致异常

现在,这个问题可以通过明确定义主体和依赖项来解决——正如异常所表明的那样。但在您的模型中,约定——即假设一对一的关系——是不正确的。实际上,您需要两个关系,一个来自
CreatedBy
(使用自己的外键),另一个来自
ModifiedBy
(使用另一个外键)。这两种关系都是一对多关系(因为
用户可以是许多其他用户的创建者或修改者),并且在关系的另一端没有导航集合。必须使用Fluent API提供映射以覆盖约定并定义这两个一对多关系:

public class UnicornsContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<UserProfile> UserProfiles { get; set; }
    public DbSet<CaseType> CaseTypes { get; set; }
    // ... etc.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasOptional(u => u.CreatedBy)
            .WithMany()
            .Map(m => m.MapKey("CreatedBy")); // FK column name in DB table

        modelBuilder.Entity<User>()
            .HasOptional(u => u.ModifiedBy)
            .WithMany()
            .Map(m => m.MapKey("ModifiedBy")); // FK column name in DB table
    }
}
…或该类的Fluent API中的映射

modelBuilder.Entity<TrackableEntity>()... // NO!
modelBuilder.Entity()…//不
…或将该类用作任何其他类中的导航属性:

public class SomeEntity
{
    //...
    public virtual TrackableEntity Something { get; set; } // NO!
    public virtual ICollection<TrackableEntity> Somethings { get; set; } // NO!
}
公共类实体
{
//...
公共虚拟可跟踪实体某物{get;set;}//NO!
公共虚拟ICollection something{get;set;}//否!
}

使用其中任何一个,EF都会将
TrackableEntity
推断为一个实体,并在模型表和数据库表之间引入继承映射(默认情况下为TPH)。否则,
TrackableEntity
只是一个基类,基类中的每个属性都将被视为派生实体中的属性,并映射到数据库表。

是否希望TrackableEntity的所有属性都是每个表右侧的非键列?这是正确的。我已经更新了我的问题,以显示我正在寻找的表结构。SQL Server不可能使用此表结构,因为它在
用户
表中引入循环关系。这就是我需要的。我想我对继承的想法是正确的,只是没有完全掌握与用户表和我的TrackableEntity的关系。谢谢你的帮助!
modelBuilder.Entity<TrackableEntity>()... // NO!
public class SomeEntity
{
    //...
    public virtual TrackableEntity Something { get; set; } // NO!
    public virtual ICollection<TrackableEntity> Somethings { get; set; } // NO!
}