ata*_*ati 3 c# asp.net-mvc ef-database-first asp.net-identity-2
我在ASP.NET MVC应用程序中使用ASP.NET Identity(数据库优先)。我按照此处的说明使用数据库优先方法设置ASP.NET Identity。
我的AspNetUsers表与Employee表有关系(Employee表具有UserId外键,AspNetUsers实体具有ICollection<Employee>属性)。
我想将ICollection<Employee>属性添加到ApplicationUser,如下所示:
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ICollection<Employee> Employees { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> 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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我这样做时,会收到以下错误消息:
EntityType'AspNetUserLogins'没有定义键。定义此EntityType的键。AspNetUserLogins:EntityType:EntitySet'AspNetUserLogins'基于类型'AspNetUserLogins',但未定义键。
为什么会收到此错误消息?我该如何解决?
即使我在没有键和关系的另一个数据库中创建表,也无法重现该问题。因此,我确定您的模型有问题。不幸的是,您没有添加我可以比较的代码,因此我无法分辨出不同之处并直接回答问题。我唯一能做的就是展示对我有用的东西。但是,首先我要说一些话。
我认为您不应该关注这篇文章。由于没有理由将上下文添加到现有数据库。
就像伊万·斯托耶夫(Ivan Stoev)提到的那样,您不应混合使用上下文。身份上下文旨在对用户进行身份验证。它存储凭据,用户角色和声明。声明旨在添加有关用户的身份信息。
实际上,默认 Hometown可以删除ApplicationUser模板字段,因为它是一个身份声明,应存储在AspNetUserClaims表中。不需要为ApplicationUser扩展它。实际上,我想不出任何理由来扩展ApplicationUser。
关于角色,这些并不是真正的要求,因为它们不提供任何身份信息,而是用于授权。这就是将它们存储在AspNetUserRoles表中的原因。不幸的是,角色作为角色声明被添加到身份中,这使事情变得混乱。
请注意,身份信息存在于权利要求中。这意味着应用程序不必调用Identity上下文。例如,User.IsInRole检查当前身份的角色声明,而不是表中存储的角色。
关于不同的上下文,另一个上下文(我通常将其称为业务模型)与Identity上下文没有任何共同之处。电子邮件和其他字段不属于业务模式,也没有意义。您可能会认为这些字段是多余的,但实际上并非如此。我可以使用Google帐户登录,但对于公司,请使用我的工作电子邮件地址。
保持上下文分离有几个原因。
如文章中所述:
此时,如果您需要将自己的表中的任何关系(例如外键)添加到这些表中,欢迎这样做,但不要直接或稍后在其任何POCO类上修改任何Entity Framework 2.0表。这样做会根据我收到的反馈而导致错误。
那么,如果您不应该从应用程序访问身份上下文,该如何管理信息呢?
对于当前用户,您不需要访问users表。所有信息都存在于身份声明中。访问身份上下文的唯一原因是允许用户登录。除了用户管理。
您可以通过添加对用户(用户ID)的引用来满足要求。如果您需要在报表中显示其他用户的信息(例如姓名),请在您的业务上下文中创建一个用户表来存储信息。您可以向该表添加关系,因为它是同一上下文的一部分。
如果您对此方法有疑问,请告诉我。
现在适合我的代码。就像其他人提到的那样,添加以下行不太可能:
public ICollection<Employee> Employees { get; set; }
Run Code Online (Sandbox Code Playgroud)
是原因。没有virtual关键字,我认为它甚至会被忽略(仍然为null)。
当我按照本文的步骤进行操作时,我将得到以下模型:
public class ApplicationUser : IdentityUser
{
public string Hometown { get; set; }
//public virtual ICollection<Employee> Employees { 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;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
// Disable migrations
//Database.SetInitializer<ApplicationDbContext>(null);
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我添加Employee类并取消注释上面ApplicationUser类中的行:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在数据库中,我添加了表:
CREATE TABLE [dbo].[Employees](
[Id] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[ApplicationUserId] [nvarchar](128) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
您可以使用 [ForeignKey]属性来使用其他字段名称。
您可以尝试这样做,也可以选择使两个上下文分开。