[英]Foreign Key To Microsoft.AspNet.Identity.EntityFramework.IdentityUser?
I'm in VS 2013 and have just created an MVC application.我在 VS 2013 中,刚刚创建了一个 MVC 应用程序。
I'm creating an object I intend to have a foreign key to the AspNetUsers table in the resulting database.我正在创建一个对象,我打算在结果数据库中拥有一个指向 AspNetUsers 表的外键。 The project does have an ApplicationUser (deriving from IdentityUser) that looks like a property-column match with the AspNetUsers table.
该项目确实有一个 ApplicationUser(源自 IdentityUser),它看起来像与 AspNetUsers 表匹配的属性列。
How do we properly declare a foreign key to this?我们如何正确地为此声明一个外键?
public MyObject
{
public string UserId { get; set; }
[ForeignKey("UserId")]
public ApplicationUser User { get; set;}
// other properties
}
Now, I modify ApplicationUser to have a collection of MyObjects:现在,我修改 ApplicationUser 以获得 MyObjects 的集合:
public ApplicationUser : IdentityUser
{
public virtual ICollection<MyObject> MyObjects { get; set; }
}
This seems to be how to do one-to-many in EF Code First.这似乎是EF Code First中如何进行一对多。 However, when I update-database, I'm getting the errors that say Identity members (IdentityUserLogin, IdentityUserRole, etc.) have no keys defined.
但是,当我更新数据库时,我收到错误消息,指出身份成员(IdentityUserLogin、IdentityUserRole 等)没有定义密钥。 Perhaps those classes were not meant to participate in EF Code First Migrations?
也许这些课程不打算参与 EF Code First 迁移?
I could go "to the back" and add the foreign key via SQL statements, but if I wanted to update again from Code First, I might get errors (that the database doesn't currently match the older migration or something like that).我可以“返回”并通过 SQL 语句添加外键,但是如果我想从 Code First 再次更新,我可能会收到错误(数据库当前与旧迁移不匹配或类似)。
How do we properly foreign-key reference those membership tables?我们如何正确使用外键引用这些成员资格表?
I also tried to create an AspNetUser class with matching properties of the AspNetUsers table.我还尝试使用 AspNetUsers 表的匹配属性创建一个 AspNetUser 类。 Instead of "public ApplicationUser" on the Client class, I declared "public AspNetUser".
我在 Client 类上声明了“public AspNetUser”,而不是“public ApplicationUser”。 Doing this resulted in a migration failure - "Automatic migration was not applied because it would result in data loss."
这样做会导致迁移失败 - “未应用自动迁移,因为它会导致数据丢失。”
So, what to do?那么,该怎么办?
It is easy to create a one-to-many relationship between ApplicationUser
and MyObject
and add a "UserId" foreign key in your MyObjects
table.在
ApplicationUser
和MyObject
之间创建一对多关系并在MyObjects
表中添加“UserId”外键很容易。 What I like about this solution is that it follows EF conventions and there is no need for [ForeignKey]
attribute in your model:我喜欢这个解决方案的地方在于它遵循 EF 约定,并且您的模型中不需要
[ForeignKey]
属性:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<MyObject> MyObjects { get; set; }
}
public class MyObject
{
public int MyObjectId { get; set; }
public string MyObjectName { get; set; }
// other properties
public virtual ApplicationUser ApplicationUser { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<MyObject> MyObjects { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyObject>()
.HasRequired(c => c.ApplicationUser)
.WithMany(t => t.MyObjects)
.Map(m => m.MapKey("UserId"));
}
}
Notice the use of Fluent API to create a "UserId" foreign key in your MyObjects
table.请注意使用 Fluent API 在
MyObjects
表中创建“UserId”外键。 This solution would still work without adding the Fluent API, but then your foreign key column would be named "ApplicationUser_Id" in your MyObjects
table by convention.此解决方案在不添加 Fluent API 的情况下仍然可以工作,但是按照惯例,您的外键列将在
MyObjects
表中命名为“ApplicationUser_Id”。
I would do the following: In the ApplicationUser
class, add a ForeignKey
attribute,我将执行以下操作:在
ApplicationUser
类中,添加一个ForeignKey
属性,
public ApplicationUser : IdentityUser {
[ForeignKey("UserID")]
public virtual ICollection<MyCustomUser> MyCustomUsers{ get; set; }
}
and in your model where you want to track to which user it belongs,在您想要跟踪它属于哪个用户的模型中,
public MyObject {
public string UserId { get; set; }
// other properties
}
You don't need to store the whole ApplicationUser
instance in the MyObject
class, and the UserID
will be generated automatically.您不需要将整个
ApplicationUser
实例存储在MyObject
类中, UserID
将自动生成。 It is important that is is of type string
, as is the ID
of the ApplicationUser
!重要的是它是
string
类型, ApplicationUser
的ID
也是如此!
public MyObject
{
.. other properties
[MaxLength(128), ForeignKey("ApplicationUser")]
public virtual string UserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set;}
}
The ASP.NET Identity classes doesn't use attributes to define the relations, they expect the relations to be configured by the DbContext. ASP.NET Identity 类不使用属性来定义关系,它们希望由 DbContext 配置关系。
The default DbContext used with ASP.NET Identity, IdentityDbContext<TUser>
includes the configuration.与 ASP.NET Identity 一起使用的默认 DbContext
IdentityDbContext<TUser>
包括配置。 So if you make your DbContext class inherit from IdentityDbContext<ApplicationUser>
you should be all set.所以如果你让你的 DbContext 类继承自
IdentityDbContext<ApplicationUser>
你应该一切都准备好了。
Update更新
If you still get error: "Automatic migration was not applied because it would result in data loss."如果仍然出现错误:“未应用自动迁移,因为它会导致数据丢失。” then do:
然后做:
get Update-Database -Force
If you still get error messages about IdentityUserLogin, IdentityUserRole, etc. have no keys defined then you most likely are overriding the OnModelCreating
method in your DbContext without calling the base method first.如果您仍然收到有关 IdentityUserLogin、IdentityUserRole 等未定义键的错误消息,那么您很可能在未先调用基本方法的情况下覆盖了
OnModelCreating
中的 OnModelCreating 方法。 Add a call to the base like this:像这样添加对基的调用:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelbuilder);
// your code here
}
End of Update更新结束
If you don't want to inherit from IdentityDbContext
you need to add some configuration for the Identity classes.如果您不想从
IdentityDbContext
继承,则需要为 Identity 类添加一些配置。 One way to do this is by overriding OnModelCreating
.一种方法是覆盖
OnModelCreating
。 This is where IdentityDbContext<ApplicationUser>
configure the entity framework mappings.这是
IdentityDbContext<ApplicationUser>
配置实体框架映射的地方。 If you add this to your DbContext class it should set up the mappings you need.如果您将此添加到您的 DbContext 类,它应该设置您需要的映射。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
}
I think you have it backwards.我认为你有它倒退。 Maybe try something like:
也许尝试这样的事情:
public MyCustomUser : IUser
{
public string Id { get; set; }
public string FavoriteHairColor { get; set;}
}
public ApplicationUser : IdentityUser
{
public virtual ICollection<MyCustomUser> MyCustomUsers{ get; set; }
}
I'm going from memory here so I might be a little off.我从这里开始记忆,所以我可能有点不对劲。 Anyway, the important things is to have your EF user class inherit from IUser.
无论如何,重要的是让您的 EF 用户类继承自 IUser。
this is also an alternative way for @kimbaudi suggestion.这也是@kimbaudi 建议的另一种方式。 With this, you don't need to define mapping key attribute instead you can use your own defined Model attribute.
有了这个,您不需要定义映射键属性,而是可以使用自己定义的模型属性。
public class MyObject
{
public string UserId { get; set; }
public ApplicationUser User { get; set; }
// other properties
}
public class ApplicationUser : IdentityUser
{
public virtual ICollection<MyObject> MyObjects { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<MyObject> MyObjects { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyObject>()
.HasRequired(po => po.User)
.WithMany(a => a.MyObjects)
.HasForeignKey(po => po.UserId);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.