为什么EF生成外键
本文关键字:EF 为什么 | 更新日期: 2023-09-27 18:27:33
我需要一对一(可选)。
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);
}
当我运行"添加迁移初始化"时,我检查生成的迁移,并查看:
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);
但我有属性UserId。为什么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;
}
}
在实体框架中建立1:0.1关系时,第一个实体的主键必须与第二个实体的私钥相同。不能指定哪个特性是FK,因为它不是必需的。我将解释:
如果User
只有一个PinnacleAccount
,则为1:0.1关系。因此,每个PinnacleAccount
都属于一个User
。这意味着,PinnacleAccount
是一个弱实体,因此,它的主键也是一个User
外键。
PinnacleAccount
不应该有自己的Id,而应该只有UserId。所以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; }
}
映射:
modelBuilder.Entity<PinnacleAccount>().HasKey(x => x.UserId);
modelBuilder.Entity<User>()
.HasOptional(i => i.PinnacleAccount)
.WithRequired(x => x.User);
这是建立1:0.1关系的唯一方法。
希望它能有所帮助!
也许您需要在映射关系的模型中声明
this.HasOptional(t => t.User)
.WithMany(t => t.PinnacleAccount)
.HasForeignKey(d => d.UserId);
正如您所知,EF基于约定、属性和您正在使用的Fluent API创建模型和相应的迁移。而且,除非你另有说明,否则约定只是在大多数情况下都能正常工作的内置约定。
由于您没有明确指定FK特性,因此正在使用约定。"通常"的约定会选择UserId
作为FK。但是,类型不匹配,因为PinnacleAccount
的UserId
只是一个字符串,而根据创建的User_Id
(AspNetUsers
表上的主键),UserId
是一个长度为128的字符串。
因此,如果使用[MaxLenght]
属性或.hasMaxLength()
fluent API将UserId
的长度定义为128,则约定会将其用于外键。
@Fabio Luz给出了正确的答案,但对于任何已经建立了错误关系并需要纠正的人,以下是我的做法。
我的"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; }
}
我可以从PinnacleAccount访问用户,但不能反过来,我想纠正这一点。为此,我必须创建两个迁移。
首先,我将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);
}
这允许我释放UserId列名称,并用UserId填充User_Id列(因为这是alter语句)。
然后我把类改成这样:
public class PinnacleAccount
{
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
}
随后,@Fabio Luz对映射进行了更改。
然后我创建了第二个迁移,看起来像:
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");
}
这给了我正确的1:0.1。感谢法比奥展示了如何正确创建一个!