【问题标题】:Mapping 1 to 0..1 in Entity Framework Code First在实体框架代码优先中将 1 映射到 0..1
【发布时间】:2015-05-27 14:48:50
【问题描述】:

我试图让 1 到 0..1 映射在 Entity Framework Code First 中工作,但不断收到错误: ReferentialConstraint 中的依赖属性映射到存储生成的列。列:'Id'。

我有一个带有必需位置的 MainLocation,但由于位置可以有多个子位置,因此 Location 对象中不需要 MainLocation。

MainLocation 与 MainLocationAddress 有类似的关系,但这是一个 1 对 1 的关系,而这又构成了同一个 db 表。

ER 模型应如下所示:

我的实体如下所示:

[Table("MainLocation")]
public class MainLocation : IEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public virtual MainLocationAddress Address { get; set; }
    [Required]
    public virtual Location Location { get; set; }
}

[Table("MainLocation")]
public class MainLocationAddress : BaseAddress
{
    [Key, ForeignKey("MainLocation")]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }
    public virtual MainLocation MainLocation { get; set; }
}

public class Location : IEntity
{
    public int Id { get; set; }
    public virtual Location ParentLocation { get; set; }
    public virtual ICollection<Location> ChildLocations { get; set; }
    protected virtual MainLocation MainLocation { get; set; }
    internal MainLocation GetMainLocation() { return this.MainLocation; }
    internal void SetMainLocation(MainLocation mainLocation) { MainLocation = mainLocation; }
}

我已经在我的 DbContext 类的 OnModelCreating 中配置了关联:

modelBuilder.Entity<MainLocation>()
            .HasRequired(x => x.Location)
            .WithOptional();

modelBuilder.Entity<MainLocation>()
            .HasRequired(x => x.Address)
            .WithRequiredPrincipal();

PS! Location 上的 MainLocation 属性受到保护,因为不应直接访问它。相反,我有一个服务层,它从位置获取值或从父位置获取继承值。我试图将其更改为公开,以查看它是否对我遇到的错误进行了任何更改。

虽然我能够将 .WithOptional() 扩展为 .WithOptional(x => x.MainLocation),但所述错误仍然没有变化。

【问题讨论】:

    标签: c# entity-framework ef-code-first fluent-interface


    【解决方案1】:

    我已经实现了两个实体 Person 和 User 之间的 1:0-1 关联。要求,一个用户必须有一个且只有一个人;而一个人可能会也可能不会与用户相关联。

    public class Person
    {
        public int PersonId { get; set; }
        public virtual User User { get; set; }
    }
    
    public class User
    {
        public int UserId { get; set; }
        public int PersonId { get; set; }
        public virtual Person Person { get; set; }
    }
    

    如下定义 EntityTypeConfiguration 类,并将它们包含在 DbContext OnModelCreating 方法中。

    public class PersonConfiguration : EntityTypeConfiguration<Person>
    {
        public PersonConfiguration()
        {
            ToTable("People");
            HasKey(p => p.PersonId);
            Property(p => p.PersonId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            HasOptional(p => p.User).WithRequired(u => u.Person); // User is option here but
                                                                  // Person is required in User
        }
    
    }
    
    public class UserConfiguration : EntityTypeConfiguration<User>
    {
        public UserConfiguration()
        {
    
            ToTable("Users");
            HasKey(u => u.UserId);
            Property(u => u.UserId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            // Create a unique index in the Users table on PersonId
            Property(u => u.PersonId).IsRequired().HasColumnAnnotation("Index",
                new IndexAnnotation(new IndexAttribute("IX_PersonId") { IsUnique = true }));
    
         }
    
    }
    

    将以下行放入 DbContext.OnModelCreating 方法中。

            modelBuilder.Configurations.Add(new PersonConfiguration());
            modelBuilder.Configurations.Add(new UserConfiguration());
    

    运行 Add-Migration 命令,您将在 DbMigration,Up 方法中得到类似以下内容。进行如下更改。

            CreateTable(
                "dbo.Users",
                c => new
                    {
                        Id = c.String(nullable: false, maxLength: 128),
                        PersonId = c.Int(nullable: false),
                        Person_PersonId = c.Int(nullable: false), // Delete this
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.People", t => t.Person_PersonId) // change to .ForeignKey("dbo.People", t => t.PersonId)
                .Index(t => t.PersonId, unique: true)  // append a ';'
                .Index(t => t._Person_PersonId); // Delete this
    
            CreateTable(
                "dbo.People",
                c => new
                    {
                        PersonId = c.Int(nullable: false, identity: true),
                   })
                .PrimaryKey(t => t.PersonId)
    

    修改 Down() 方法如下。

    改变

     DropForeignKey("dbo.Users", "Person_PersonId", "dbo.People");
    

     DropForeignKey("dbo.AppUsers", "PersonId", "dbo.People");
    

    改变

     DropIndex("dbo.AppUsers", new[] { "Person_PersonId" });
    

     DropIndex("dbo.AppUsers", new[] { "PersonId" });
    

    运行针对此迁移的 Update-Database 命令。生成的 Users 和 People 表将在 PersonId 外键上具有一对一的关联。

    【讨论】:

      【解决方案2】:

      我已经意识到这在 EF 中是不可能实现的,因为目前(1 到 0..1 关联)。

      我已经在我们的解决方案中通过让所有子位置都引用主位置来解决这个问题。我仍然可以通过寻找没有父位置的位置来获得顶级组织。所以,虽然这不是我们想要的,但它不会破坏我们的商业模式。

      【讨论】:

        【解决方案3】:

        此方案在 Update-Database 上运行良好,因为所需的数据库结构显示了 User 和 People 表之间的一对一关系。但是,出于某种原因,尝试查询 Users 表。

        我通过删除 PersonId 属性更改了 User 类。

        public class User
        {
            public int UserId { get; set; }
            public virtual Person Person { get; set; }
        }
        

        UserConfiguration 类变为:

        public class UserConfiguration : EntityTypeConfiguration<User>
        {
            public UserConfiguration()
            {
        
                ToTable("Users");
                HasKey(u => u.UserId);
                Property(u => u.UserId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        
             }
        
        }
        

        添加迁移产生: 创建表( "dbo.Users", c => 新的 { Id = c.String(可为空:假,最大长度:128), Person_PersonId = c.Int(nullable: false), // 保留这个 }) .PrimaryKey(t => t.UserId) .ForeignKey("dbo.People", t => t.Person_PersonId) .Index(t => t._Person_PersonId); // 改为 .Index(t => t._Person_PersonId, unique: true);

        Update-Database 生成具有一对一关系的 User 和 People 表,并且框架使用自己生成的 Person_PersonId 列。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多