ASP.NET MVC 5 实体框架 - 关系

本文关键字:框架 关系 实体 NET MVC ASP | 更新日期: 2023-09-27 18:34:15

我目前正在开发一个Web应用程序。我正在使用标识作为用户的身份验证和角色。

我希望我的应用程序中的每个用户都有一个关联的"机构"。该机构包含名称和描述。这是我的 IdentityUser 类:

    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;
        }
        [Display(Name="Institution")]
        public Institution Institution { get; set; }
    }

当我更新数据库时,将执行 Seed 方法,而这个,我正在创建一个具有"管理员"角色的用户,并关联一个机构。这是我的种子方法:

if (!context.Users.Any(u => u.UserName == "mxfragz"))
{
    var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new IdentitiesDb()));
    roleManager.Create(new IdentityRole("admin"));
    var store = new UserStore<ApplicationUser>(context);
    var manager = new UserManager<ApplicationUser>(store);
    var user = new ApplicationUser { UserName = "mxfragz" };
    user.Institution = new Institution() { Name = "London", Description="Description" };
    manager.Create(user, "password");
    manager.AddToRole(user.Id, "admin");
}

我的问题是,当我在我的 Web 应用程序中创建新用户时,我找不到关联现有机构的方法(此处仅创建"伦敦"(。到目前为止,当我创建用户时,我会获取所选机构的 ID 并找到现有机构,以便将其与用户中定义的机构属性相关联。当我这样做时,实体框架不会关联已找到的现有机构,而是创建一个新机构,并将其关联到我的用户。我最终得到了 2 个具有相同名称和描述的不同机构。这是我的代码:

public async Task<ActionResult> Create(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser() { UserName = model.Username, Email = string.Empty };
        int selected = int.Parse(model.SelectedInstitution);
        user.Institution = new InstitutionsDb().Institutions.Where(x => x.Id == selected).First();
        IdentityResult result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new IdentitiesDb()));
            UserManager.AddToRole(user.Id.ToString(), roleManager.Roles.Where(x => x.Id == model.SelectedRole.ToString()).First().Name);
            return RedirectToAction("Index", "Users");
        }
        else
        {
            AddErrors(result);
        }
    }
    model.Roles = GetRoles();
    model.Institutions = GetInstitutions();
    return View(model);
}

我找到了几个关于使用 Attach 方法的主题,但即使我尝试使用它,它也不起作用。我做错了什么吗?或者有什么办法可以做我想做的事情吗?

ASP.NET MVC 5 实体框架 - 关系

外键关系需要通过机构上的虚拟集合以及应用程序用户上的实际外键值公开。

public class ApplicationUser : IdentityUser
{
    //...
    public int InstitutionId { get; set; }
    [Display(Name="Institution")]
    [ForeignKey("InstitutionId")] //This attribute isn't strictly necessary but adds clarity
    public Institution Institution { get; set; }
}
public class Institution
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<User> Users { get; set; }
}

EF 将根据如下所示的机构 ID 自动将关联的机构附加到虚拟财产上。

我建议只将DbSet<Institutions>添加到ApplicationDbContext而不是它自己的InstitutionsDb上下文中,这可能是您问题的一部分,因为UserManager仅绑定到您在IdentityConfig.cs文件中配置的ApplicationDbContext或上下文。

public async Task<ActionResult> Create(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser() { UserName = model.Username, Email = string.Empty };
        int selected = int.Parse(model.SelectedInstitution);
        var context = HttpContext.GetOwinContext().Get<ApplicationDbContext>()
        //Set the id
        user.InstitutionId = context.Institutions.Where(x => x.Id == selected).First().Id;          
        IdentityResult result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new IdentitiesDb()));
            UserManager.AddToRole(user.Id.ToString(), roleManager.Roles.Where(x => x.Id == model.SelectedRole.ToString()).First().Name);
            return RedirectToAction("Index", "Users");
        }
        else
        {
            AddErrors(result);
        }
    }
    model.Roles = GetRoles();
    model.Institutions = GetInstitutions();
    return View(model);
}

这应该允许您在从UserManager检索ApplicationUser时调用user.Institution.Name