ApplicationUser有一个ApplicationUser

时间:2018-04-04 15:53:58

标签: asp.net entity-framework asp.net-identity dbcontext

我构建了一个新的Web应用程序,它使用Visual Studio提供的模板并包含MVC和Web API。默认授权机制是Identity,数据库交互是使用Entity Framework和Code-first方法创建数据库完成的。

我有三个要求:

  1. 用户可以拥有儿童对象列表
  2. 我不想使用"关系"对象
  3. 所有用户都已存在于AspNetUsers表中,因为它们都需要能够登录,因此我不希望其他表维护用户数据
  4. 理论上,多个父母可以参考多个孩子,但是对于这个例子,我们只会将其视为一对多的关系。

    在我的应用程序中,我需要ApplicationUser有一个ChildUsers列表作为ApplicationUser的集合,如下所示。

    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string PostalCode { get; set; }
        public string ShirtSize { get; set; }
    
        public ICollection<ApplicationUser> Children { get; set; }
    }
    

    我希望这些用户可以访问,如上所示(ApplicationUser的集合),而不是将Relationship对象绑定在一起的集合,例如:

    public class Relationship
    {
        public String ParentId { get;set; }
        public String ChildId { get;set; }
    }
    

    是否可以在数据库中创建并存在新表,而无需使用代码优先模型来了解如何创建关系表?

    这个问题的解决方案是什么?

1 个答案:

答案 0 :(得分:0)

经过一些研究和实验,我找到了一些指导,以找到有效的解决方案。

为了创建一个中间表来维护关系,ApplicationDbContext OnModelCreating函数需要知道它应该是什么样子。我告诉它使用下面代码中显示的modelBuilder创建一个未绑定到对象的新表。不幸的是,我没有指向我的文章的链接。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base( "DefaultConnection", throwIfV1Schema: false )
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating( DbModelBuilder modelBuilder )
    {
        base.OnModelCreating( modelBuilder );
        modelBuilder.Entity<ApplicationUser>()
            .HasMany( p => p.ChildUsers )
            .WithMany()
            .Map( m =>
             {
                 m.MapLeftKey( "Father_Id" );
                 m.MapRightKey( "Son_Id" );
                 m.ToTable( "father_son_relation" );
             } );
    }
}

此外,当您需要将Child添加到父ApplicationUser时,您需要在插入时进行一些调整,以便正确更新数据库。我绝对希望UserManager为我创建用户,但这意味着当我使用下面的代码将用户添加到我的Child列表中时,它会尝试再次添加它并抛出异常因为它已经存在。

var result = await UserManager.CreateAsync( user, model.Password );
var myUserId = User.Identity.GetUserId();
var users = AppDbContext.Users.Where( u => u.Id == myUserId ).Include( u => u.ChildUsers );
var u2 = users.First();
u2.ChildUsers.Add( user );
await AppDbContext.SaveChangesAsync();

找到this question后,我研究了EntityState,发现在调用SaveChanges之前添加以下行解决了异常,并且不再尝试再次添加它。

AppDbContext.Entry( user ).State = EntityState.Unchanged;

TADA !!!现在,使用EF从数据库中选择它们,然后可以使用以下代码:

AppDbContext.Users.Where( u => u.Id == myUserId ).Include( u => u.Children ).First();

因为我只获得一个级别的孩子,所以这样可以正常工作,之后你冒着循环引用的风险。

欢迎提出改进代码的意见和建议。