简体   繁体   English

为什么EF会生成外键?

[英]Why EF generate foreign key?

I need make one to one (optional). 我需要一对一(可选)。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<PinnacleAccount>().HasKey(x => x.Id);

    modelBuilder.Entity<PinnacleAccount>()
        .HasRequired(x => x.User)
        .WithOptional(x => x.PinnacleAccount);

    base.OnModelCreating(modelBuilder);
}

and when I run 'Add-Migration Init' I check generated migration and see: 当我运行'Add-Migration Init'时,我检查生成的迁移并查看:

CreateTable(
                "dbo.PinnacleAccounts",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        ClientId = c.String(),
                        Password = c.String(),
                        PercentForBet = c.Int(nullable: false),
                        UserId = c.String(),
                        User_Id = c.String(nullable: false, maxLength: 128),
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.AspNetUsers", t => t.User_Id)
                .Index(t => t.User_Id);

But I have property UserId. 但我有属性UserId。 Why ef create User_Id 为什么ef创建User_Id

   public class ApplicationUser : IdentityUser
    {
        public virtual PinnacleAccount PinnacleAccount { get; set; }
        public int? PinnacleAccountId { get; set; }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }

When you make a 1:0.1 relationship in entity framework, the primary key of the first entity must be same as the primary key of the second entity. 当您在实体框架中建立1:0.1关系时,第一个实体的主键必须与第二个实体的主键相同。 You can't specify which property is the FK because it is not necessary. 您无法指定哪个属性是FK,因为它不是必需的。 I will explain: 我会解释:

If a User has only one PinnacleAccount , it is a 1:0.1 relationship. 如果User只有一个PinnacleAccount ,则它是1:0.1的关系。 So, every PinnacleAccount belongs to an User . 因此,每个PinnacleAccount属于一个User It means that, PinnacleAccount is a weak entity, so, its primary key is also an User foreign key. 这意味着, PinnacleAccount是一个弱实体,因此,它的主键也是一个User外键。

PinnacleAccount should not have its own Id, just the UserId. PinnacleAccount不应该有自己的Id,只有UserId。 So, PinnacleAccount should be like this: 所以, PinnacleAccount应该是这样的:

public class PinnacleAccount
{
    public string UserId { get; set; } //PK AND FK
    public string ClientId  { get; set; }
    public string Password { get; set; }
    public string PercentForBet { get; set; }
}

Mapping: 制图:

modelBuilder.Entity<PinnacleAccount>().HasKey(x => x.UserId);
modelBuilder.Entity<User>()
    .HasOptional(i => i.PinnacleAccount)
    .WithRequired(x => x.User);

This is the only way to make 1:0.1 relationship. 这是建立1:0.1关系的唯一方法。

Hope it helps! 希望能帮助到你!

Maybe you need to declare in the model mapping the relationships 也许您需要在模型中声明映射关系

this.HasOptional(t => t.User)
                .WithMany(t => t.PinnacleAccount)
                .HasForeignKey(d => d.UserId);

As you know EF creates the model, and corresponding migrations, based on conventions, attributes, and the Fluent API you're using. 如您所知,EF根据您正在使用的约定,属性和Fluent API创建模型和相应的迁移。 And, unless you speciy otherwise, the convention areonly built-in conventions that works fine in most occassions. 并且,除非您另有说明,否则约定只是内置的约定,在大多数情况下都能正常工作。

As you're not explicilty specifying the FK property, conventions are being used. 由于您没有明确指定FK属性,因此正在使用约定。 The "usual" convention would have chosen UserId as FK. “通常”约定会选择UserId作为FK。 However, there is a type mismatch, because PinnacleAccount 's UserId is simply a string, while, according to the created User_Id , the primary key on the AspNetUsers table, UserId is an string with lenght 128. 但是,存在类型不匹配,因为PinnacleAccountUserId只是一个字符串,而根据创建的User_IdAspNetUsers表上的主键, UserId是一个长度为128的字符串。

So, if you define the length of the UserId as 128, with [MaxLenght] attribute, or with .hasMaxLength() fluent API, conventions will use it for the foreing key. 因此,如果您将UserId的长度定义为128,使用[MaxLenght]属性或使用.hasMaxLength()流畅的API,则约定将使用它作为foreing键。

@Fabio Luz has given the correct answer, but for anyone that already has an incorrect relationship set up and needs to correct it, here's how I did it. @Fabio Luz给出了正确的答案,但对于那些已经设置错误且需要纠正错误的人来说,我就是这样做的。

My 'PinnacleAccount' looked like the following (I use GUIDs, but you get the idea): 我的'PinnacleAccount'看起来如下(我使用GUID,但你明白了):

public class PinnacleAccount
{
  [Required]
  [Key]
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public Guid Id { get; set; }

  public virtual ApplicationUser User { get; set;  }
  [Required]
  public virtual string UserId { get; set; }  
}

I could access the the User from PinnacleAccount, but not the other way around, which I wanted to correct. 我可以从PinnacleAccount访问用户,但不是相反,我想纠正。 To do so, I had to create two migrations. 为此,我必须创建两个迁移。

Firstly, I edited the UserId property to be UserIdOld and created the migration which looked like: 首先,我将UserId属性编辑为UserIdOld并创建了类似于以下内容的迁移:

public override void Up()
{
    DropForeignKey("dbo.PinnacleAccount", "UserId", "dbo.AspNetUsers");
    DropIndex("dbo.PinnacleAccount", new[] { "UserId" });
    RenameColumn(table: "dbo.PinnacleAccount", name: "UserId", newName: "User_Id");
    AddColumn("dbo.PinnacleAccount", "UserIdOld", c => c.String(nullable: false));
    AlterColumn("dbo.PinnacleAccount", "User_Id", c => c.String(maxLength: 128));
    CreateIndex("dbo.PinnacleAccount", "User_Id");
    AddForeignKey("dbo.PinnacleAccount", "User_Id", "dbo.AspNetUsers", "Id");
}

public override void Down()
{
    DropForeignKey("dbo.PinnacleAccount", "User_Id", "dbo.AspNetUsers");
    DropIndex("dbo.PinnacleAccount", new[] { "User_Id" });
    AlterColumn("dbo.PinnacleAccount", "User_Id", c => c.String(nullable: false, maxLength: 128));
    DropColumn("dbo.PinnacleAccount", "UserIdOld");
    RenameColumn(table: "dbo.PinnacleAccount", name: "User_Id", newName: "UserId");
    CreateIndex("dbo.PinnacleAccount", "UserId");
    AddForeignKey("dbo.PinnacleAccount", "UserId", "dbo.AspNetUsers", "Id", cascadeDelete: true);
}

This allowed me to free up the UserId column name and it populated the User_Id column with the UserId (as that was the alter statement). 这允许我释放UserId列名,并使用UserId填充User_Id列(因为这是alter语句)。

I then changed the the class to look like: 然后我改变了类看起来像:

 public class PinnacleAccount
{
    public string UserId { get; set; }

  public virtual ApplicationUser User { get; set;  }
}

Followed by the changes to the Mapping as described by @Fabio Luz. 随后是@Fabio Luz所描述的对Mapping的更改。

I then created a second migration which looked like: 然后我创建了第二个迁移,看起来像:

public override void Up()
{
    DropIndex("dbo.PinnacleAccount", new[] { "User_Id" });
    RenameColumn(table: "dbo.PinnacleAccount", name: "User_Id", newName: "UserId");
    DropPrimaryKey("dbo.PinnacleAccount");
    AlterColumn("dbo.PinnacleAccount", "UserId", c => c.String(nullable: false, maxLength: 128));
    AddPrimaryKey("dbo.PinnacleAccount", "UserId");
    CreateIndex("dbo.PinnacleAccount", "UserId");
    DropColumn("dbo.PinnacleAccount", "Id");
    DropColumn("dbo.PinnacleAccount", "UserIdOld");
}

public override void Down()
{
    AddColumn("dbo.PinnacleAccount", "UserIdOld", c => c.String(nullable: false));
    AddColumn("dbo.PinnacleAccount", "Id", c => c.Guid(nullable: false, identity: true));
    DropIndex("dbo.PinnacleAccount", new[] { "UserId" });
    DropPrimaryKey("dbo.PinnacleAccount");
    AlterColumn("dbo.PinnacleAccount", "UserId", c => c.String(maxLength: 128));
    AddPrimaryKey("dbo.PinnacleAccount", "Id");
    RenameColumn(table: "dbo.PinnacleAccount", name: "UserId", newName: "User_Id");
    CreateIndex("dbo.PinnacleAccount", "User_Id");
}

That gave me the correct 1:0.1. 这给了我正确的1:0.1。 Thanks to Fabio for showing how to create one properly! 感谢Fabio展示如何正确创建一个!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM