mod*_*777 7 c# sql-server entity-framework ef-code-first
我将EntityFramework 6.1.3与 CodeFirst 一起用于 Asp.Net 应用程序。我有一个现有表(“Users”),我试图在其中添加外键“GroupId”。这是类(带有 //new 的所有内容都是上次迁移后所做的更改)
[Table("Users")]
public class User
{
[Key]
[Column("PK_USER")]
public int Id { get; set; }
[Column("Username")]
public string Username { get; set; }
[Column("Name")]
public string Name { get; set; }
[Column("Password")]
public string Password { get; set; }
[Column("Firstname")]
public string Firstname { get; set; }
[Column("Lastname")]
public string Lastname { get; set; }
[Column("LastLogin")]
public DateTime? LastLogin { get; set; }
[Column("Department")]
public string Department { get; set; }
[Column("EMail")]
public string EMail { get; set; }
[Column("IsWindowsUser")]
public bool? IsWindowsUser { get; set; }
[Column("Signature")]
public string Signature { get; set; }
[Column("FK_ROLE")]
public int? RoleId { get; set; }
[ForeignKey("RoleId")]
public virtual Role Role { get; set; }
// new
[Column("GroupId")]
public int? GroupId { get; set; }
//new
[ForeignKey("GroupId")]
public virtual Group Group { get; set; }
//new
public virtual ICollection<GroupResponsibility> Responsibilites { get; set; }
public virtual ICollection<UserField> UserFields { get; set; }
public override string ToString()
{
return Username;
}
}
Run Code Online (Sandbox Code Playgroud)
运行add-migration后生成以下代码(省略其他更改)
AddColumn("dbo.Users", "GroupId", c => c.Int());
AddColumn("dbo.Users", "Group_Id", c => c.Int());
CreateIndex("dbo.Users", "GroupId");
CreateIndex("dbo.Users", "Group_Id");
AddForeignKey("dbo.Users", "Group_Id", "dbo.Groups", "Id");
AddForeignKey("dbo.Users", "GroupId", "dbo.Groups", "Id");
Run Code Online (Sandbox Code Playgroud)
如您所见,EntityFramework 识别了外键,但仍添加了默认的“Group_Id”。如果我完成并更新数据库,导航属性“Group”将关联到“Group_Id”而不是所需的“GroupId”。
任何想法可能导致这种情况?
我注释掉了导航属性并得到了相同的结果。看起来关系另一端的 ICollection用户是罪魁祸首。这是“组”类
[Table("Groups")]
public class Group
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? GroupLeaderId { get; set; }
[ForeignKey("GroupLeaderId")]
public virtual User GroupLeader { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<GroupResponsibility> Responsibilites { get; set; }
public virtual ICollection<ApplicationForm> Applications { get; set; }
public override string ToString()
{
return Name;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我注释掉ICollection Users,则在添加迁移时会出现以下异常:
无法确定类型“SparePartsDb.Entities.Group”和“SparePartsDb.Entities.User”之间关联的主要端。必须使用关系流畅 API 或数据注释显式配置此关联的主体端。
在谷歌搜索并更改 Group 类上的 Key Attribute 之后......
[Key, ForeignKey("GroupLeader")]
public int Id { get; set; }
Run Code Online (Sandbox Code Playgroud)
...我可以注释掉 ICollection 并运行迁移。但是,即使用户类中存在导航属性,也不再将 GroupId 识别为外键。
AddColumn("dbo.Users", "GroupId", c => c.Int());
Run Code Online (Sandbox Code Playgroud)
好的,所以我已经在多个排列中搜索了“迁移添加重复外键”几个小时,但我终于找到了导致它的原因:不要假设 Fluent API 知道您指的是哪个字段WithOne()或WithMany()- - 指定字段。详情请见下文。
我有两个处于一对多关系的实体模型,Addressand Invitation,public virtual ICollection<Invitation> InvitationsonAddress和public virtual Address Addresson Invitation。我选择了 Fluent API 而不是约定/属性,所以我的Invitation构建器看起来像这样:
builder
.HasOne(x => x.Address)
.WithMany()
.HasForeignKey(x => x.AddressId);
Run Code Online (Sandbox Code Playgroud)
不幸的是,EF Core 2.2 不喜欢WithMany()在那里放空。运行dotnet ef migrations add InitialCreate导致了这种废话,很像OP:
migrationBuilder.CreateTable(
name: "Invitation",
columns: table => new
{
AddressId = table.Column<Guid>(nullable: false),
AddressId1 = table.Column<Guid>(nullable: true),
...
},
constraints: table =>
{
table.PrimaryKey("PK_Invitation", x => x.Id);
table.ForeignKey(
name: "FK_Invitation_Address_AddressId",
column: x => x.AddressId,
principalTable: "Address",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Invitation_Address_AddressId1",
column: x => x.AddressId1,
principalTable: "Address",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
Run Code Online (Sandbox Code Playgroud)
切换我的构建器以阅读:
builder
.HasOne(x => x.Address)
.WithMany(x => x.Invitations)
.HasForeignKey(x => x.AddressId);
Run Code Online (Sandbox Code Playgroud)
为我解决了问题。
运行dotnet ef migrations remove之后dotnet ef migrations add InitialCreate再次给了我一个更加美好的迁移:
migrationBuilder.CreateTable(
name: "Invitation",
columns: table => new
{
AddressId = table.Column<Guid>(nullable: false),
...
},
constraints: table =>
{
table.PrimaryKey("PK_Invitation", x => x.Id);
table.ForeignKey(
name: "FK_Invitation_Address_AddressId",
column: x => x.AddressId,
principalTable: "Address",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助其他一些可怜的灵魂进行搜索。
小智 0
你不应该需要放一个
\n\n[Column("GroupId")] \nRun Code Online (Sandbox Code Playgroud)\n\n在上面
\n\npublic int? GroupId { get; set; } \nRun Code Online (Sandbox Code Playgroud)\n\n实体框架应该能够自行识别您的映射。
\n\n正如msdn中所述:
\n\n\n\n\n生成数据库时,代码首先会看到 Post 类中的 BlogId 属性,并按照与类名加 \xe2\x80\x9cId\xe2\x80\x9d 相匹配的约定将其识别为 Blog 类的外键。但博客类中没有 BlogId 属性。解决方案是在 Post 中创建一个导航属性,并使用外部数据注释来帮助代码首先了解如何使用 Post.BlogId 属性 \xe2\x80\x94 来构建两个类 \xe2\x80\x94 之间的关系:以及如何在数据库中指定约束。
\n
这个解释的代码是:
\n\npublic class Post \n{ \n public int Id { get; set; } \n public string Title { get; set; } \n public DateTime DateCreated { get; set; } \n public string Content { get; set; } \n public int BlogId { get; set; } \n [ForeignKey("BlogId")] \n public Blog Blog { get; set; } \n public ICollection<Comment> Comments { get; set; } \n}\nRun Code Online (Sandbox Code Playgroud)\n\n正如您所看到的,只有复杂对象具有定义 fk 的映射,EF 应该为您完成其余的工作。
\n\n\n| 归档时间: |
|
| 查看次数: |
2402 次 |
| 最近记录: |