2 回答
TA贡献1796条经验 获得超10个赞
即使我在没有键和关系的另一个数据库中创建表,我也无法重现该问题。所以我确定你的模型有问题。不幸的是,您没有添加我可以比较的代码,所以我无法说出有什么不同并直接回答问题。我唯一能做的就是展示什么对我有用。不过,首先我要说几点。
我认为你不应该关注这篇文章。因为没有理由将上下文添加到现有数据库中。
就像 Ivan Stoev 提到的,你不应该混合上下文。身份上下文旨在对用户进行身份验证。它存储凭据、用户角色和声明。其中声明旨在添加有关用户的身份信息。
实际上,Hometown
ApplicationUser 模板的默认字段可以删除,因为它是一个身份声明,应该存储在 AspNetUserClaims 表中。不是您需要扩展 ApplicationUser 的东西。实际上,我想不出任何扩展 ApplicationUser 的理由。
关于角色,这些并不是真正的声明,因为它们没有说明身份,而是用于授权。这就是为什么它们可以存储在 AspNetUserRoles 表中的原因。不幸的是,角色作为角色声明被添加到身份中,这让事情变得混乱。
请注意,身份信息存在于声明中。这意味着应用程序不必调用身份上下文。例如 User.IsInRole 检查当前身份的角色声明,而不是存储在表中的角色。
关于不同的上下文,另一个上下文(我通常称之为业务模型)与 Identity 上下文没有任何共同之处。电子邮件和其他领域不是商业模式的一部分,也没有意义。您可能认为这些字段是多余的,但实际上并非如此。我可以使用谷歌帐户登录,但对于业务,请使用我的工作电子邮件地址。
将上下文分开有几个原因。
关注点的分离。假设您将来要与另一个身份验证框架交换身份验证框架。如果您想支持单点登录 (SSO),就像实施 IdentityServer 一样。
如果另一个应用程序需要相同的登录名,则不能将用户表移动到另一个数据库。因此,您最终还要向数据库添加其他上下文。
迁移问题。如果混合上下文,则迁移将失败。
它会让事情变得容易得多。这是您遇到的第一个问题,而不是最后一个。
正如文章中所提到的:
此时,如果您需要将任何关系(例如外键)从您自己的表添加到这些表,欢迎您这样做,但不要直接或稍后在其任何 POCO 类上修改任何实体框架 2.0 表。根据我收到的反馈,这样做会导致错误。
那么,如果您不应该从您的应用程序访问身份上下文,那么如何管理信息呢?
对于当前用户,您不需要访问 users 表。所有信息都存在于身份声明中。访问身份上下文的唯一原因是允许用户登录。除了用户管理。
您可以通过添加对用户的引用(用户 ID)就足够了。如果您需要在报告中显示其他用户的信息(如姓名),则在您的业务上下文中创建一个用户表来存储信息。您可以向该表添加关系,因为它是同一上下文的一部分。
如果您对此方法有任何疑问,请告诉我。
现在对我有用的代码。就像其他人提到的那样,不太可能添加以下行:
public ICollection<Employee> Employees { get; set; }
是原因。如果没有virtual
关键字,我认为它甚至会被忽略(保持为空)。
当我按照文章的步骤进行操作时,我最终会得到以下模型:
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();
}
}
然后我添加 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; }
}
在数据库中,我添加了表:
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]
您可以使用该[ForeignKey]属性来使用不同的字段名称。
您可以尝试这样做或选择将两个上下文分开。
TA贡献1805条经验 获得超10个赞
忧虑:
我确切地知道你在这里的负担是什么。是的,微软,一个深奥的邪教,在为这个与身份(实体框架)建立关系的问题提供信息方面做得很差。
贡献:
Ruard van Elburg 于 8 月 24 日 16:31 发表的帖子对此事给出了很好的见解;但是,我注意到他的代码中缺少一个关键组件,即需要放置在 IdentityModels 的 DBContext 中的 DbSet。
技术栈:
我提供了我的技术堆栈,以便如果这不适用于旧版本的软件,您就会知道我用什么来解决这个问题。
Visual Studio 2017 MVC 5。仅供参考,MVC 5 内置于最新的 VS 中。
SQL Server 17
MS SQL 管理工作室 17
解决方案:
免责声明!!!我知道首先关注的是数据库;但是,此解决方案仅适用于代码优先方法。但是,嘿,它有效!
在这里,我提供了有关如何执行此操作的演练。请确保您在代码的上边距中拥有所有依赖项。
步骤1:添加 public virtual DbSet<ModelNameOfInterest> ModelNameOfInterest { get; set; }
到public class ApplicationDbContext : IdentityDbContext<ApplicationUser>{}
如在下面看到的代码。
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.ComponentModel.DataAnnotations.Schema;
namespace AwesomeCode.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
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)
{
}
//A virtul DbSet in order to interact with the autogenerated code the identity framewrok produces.
public virtual DbSet<ModelNameOfInterest> ModelNameOfInterest { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
}
第 2 步:添加public virtual ApplicationUser ApplicationUser { get; set; }到您要与之建立关系的模型中,如下所示。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace AwesomeCode.Models
{
public class WorkExp
{
[Key]
public int Id { get; set; }
public string JobTitle { get; set; }
//Create foreign key with reference to ApplicationUser_Id that was auto-generated by entity framework.
public virtual ApplicationUser ApplicationUser { get; set; }
}
}
第 3 步:鉴于您为数据库设置了连接字符串,您需要生成迁移。包管理器控制台的路径:工具->NuGet Packer Manager->包管理器控制台
如果根目录中不存在迁移文件夹,则启用迁移:在
PM>
键入之后,Enable-Migrations
您应该会看到一个包含两个文件的迁移文件夹。启用迁移后: After
PM>
,请键入Update-Database
You should see tables in your database now。添加另一个迁移: After
PM>
,键入Add-Migration
AfterName:
,键入InitialCreate
或Your model of interest
您现在应该会在您的数据库中看到表。您现在应该可以看到数据库中的表。
第 4 步:仔细检查感兴趣的模型的外键是否正确引用到 AspNetUser 表。在 MS Management Studio 中,您可以创建关系图来显示引用。你可以在谷歌上找到如何做到这一点。
第 5 步:一如既往地保持冷静、冷静和镇定。
- 2 回答
- 0 关注
- 229 浏览
添加回答
举报