【问题标题】:ApplicationUser has a list of ApplicationUserApplicationUser 有一个 ApplicationUser 列表
【发布时间】:2018-04-04 15:53:58
【问题描述】:

我已经构建了一个新的 Web 应用程序,它使用 Visual Studio 提供的模板并包含 MVC 和 Web API。默认授权机制是身份,数据库交互是使用实体框架和代码优先创建数据库的方法完成的。

我有三个要求:

  1. 用户可以拥有一个子对象列表
  2. 我不想使用“关系”对象
  3. 所有用户都已经存在于 AspNetUsers 表中,因为他们都需要能够登录,所以我不希望另一个表来维护用户数据

理论上,多个父级可以引用多个子级,但对于本示例,我们将仅将其视为一对多关系。

在我的应用程序中,我需要有一个 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; }
}

是否可以在没有代码优先模型的情况下创建新表并将其存在于数据库中以使其知道如何创建关系表?

有什么办法可以解决这个问题?

【问题讨论】:

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


    【解决方案1】:

    经过一些研究和实验,我找到了一些指导意见,可以找到可行的解决方案。

    为了创建一个中间表来维护关系,ApplicationDbContextOnModelCreating 函数需要知道它应该是什么样子。我已经告诉它使用下面代码中显示的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" );
                 } );
        }
    }
    

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

    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后,我研究了EntityStates,发现在调用SaveChanges之前添加以下行解决了异常,不再尝试再次添加。

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

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

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

    由于我只获得一个级别的儿童,这将可以正常工作,之后您将面临循环引用的风险。

    欢迎提出改进代码的意见和想法。

    【讨论】:

      猜你喜欢
      • 2017-03-16
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多