我构建了一个新的Web应用程序,它使用Visual Studio提供的模板,并包含MVC和Web API。 默认授权机制是 Identity,数据库交互是使用实体框架和创建数据库的代码优先方法完成的。
我有三个要求:
- 用户可以拥有子对象列表
- 我不想使用"关系"对象
- 所有用户都已存在于 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; }
}
是否可以在没有代码优先模型的情况下创建新表并将其存在于数据库上,以便它知道如何创建关系表?
这个问题有哪些可用的解决方案?
经过一些研究和实验,我找到了一些指导,以得出一个有效的解决方案。
为了创建中间表来维护关系,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" );
} );
}
}
此外,当您需要将子项添加到父ApplicationUser
时,您需要在要插入时进行一些调整,以便正确更新数据库。 我绝对希望UserManager
为我创建用户,但这意味着当我使用以下代码将用户添加到我的 Children 列表中时,它会尝试再次添加它并抛出异常,因为它已经存在。
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();
找到这个问题后,我研究了EntityState
,发现在调用之前添加以下行SaveChanges
解决了异常,它不再尝试再次添加它。
AppDbContext.Entry( user ).State = EntityState.Unchanged;
多田!! 现在,若要使用 EF 从数据库中选择它们,可以使用以下代码:
AppDbContext.Users.Where( u => u.Id == myUserId ).Include( u => u.Children ).First();
由于我只获得了一个级别的儿童,因此可以正常工作,之后您将冒循环引用的风险。
欢迎提出改进代码的评论和想法。