我需要帮助,因为我正努力在我的应用程序中建立多对多的关系。
我的模特:
public class BaseEntity
{
[Key, Required]
public Guid Id { get; set; }
public DateTime Created { get; set; }
#region reference
public Guid CreatedBy { get; set; }
#endregion
public BaseEntity()
{
Id = Guid.NewGuid();
Created = DateTime.Now;
}
}
public class Person : BaseEntity
{
/// <summary>
/// Firstname of the person. Required
/// </summary>
[Required]
public string FirstName { get; set; }
/// <summary>
/// Middlename of the contact person. Not required
/// </summary>
public string MiddleName { get; set; }
/// <summary>
/// Lastname of the contact person. Required
/// </summary>
[Required]
public string LastName { get; set; }
public Gender Gender { get; set; }
[NotMapped]
public string FullName
{
get
{
StringBuilder sb = new StringBuilder();
sb.Append(FirstName);
if (!string.IsNullOrEmpty(MiddleName))
sb.Append($" {MiddleName}");
sb.Append($" {LastName}");
return sb.ToString().TrimEnd(' ');
}
}
}
public class User : Person
{
#region public properties
[Required]
public string UserName { get; set; }
[Required]
public string Email { get; set; }
[Required]
public byte[] Password { get; private set; }
public byte[] Salt { get; set; }
public int WorkFactor { get; set; }
public virtual ICollection<UserRole> UserRoles { get; set; }
#endregion
#region constructor
public User() : base()
{
//security settings
Salt = SecurityHelper.GenerateSalt(12);
WorkFactor = 5;
UserRoles = new List<UserRole>();
}
#endregion
#region public methods
public void SetPassword(string password)
{
Password = SecurityHelper.GenerateHash(Encoding.UTF8.GetBytes(password), Salt, WorkFactor, 128);
}
#endregion
public bool ComparePassword(string password)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(Password, SecurityHelper.GenerateHash(Encoding.UTF8.GetBytes(password), Salt, WorkFactor, 128));
}
}
public class Role : BaseEntity
{
#region public properties
[Required]
public string ReadableId { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<SecurityPrivilege> Privileges { get; set; } = new List<SecurityPrivilege>();
public virtual ICollection<UserRole> UserRoles { get; set; }
#endregion
#region constructor
public Role() : base()
{
UserRoles = new List<UserRole>();
}
#endregion
}
public class UserRole
{
public Guid UserId { get; set; }
public Guid RoleId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
[ForeignKey("RoleId")]
public Role Role { get; set; }
}
现在,我想要完成的是,用户可以属于任意数量的角色。
在我的播种机中,我将记录添加到用户的UserRoles列表中,只要将数据存储在表格中就可以正常工作。
当我在控制器中查询(在API中)时,我无法再次检索此数据:
var user = _context.Users.Include(x => x.UserRoles).FirstOrDefault(u => u.UserName == request.UserName);
这里,UserRoles列表总是为空,即使我可以在表中看到,我应该有行,因为UserId字段与User对象匹配。
上下文定义:
public class TMContext : DbContext
{
public TMContext(DbContextOptions<TMContext> options) : base(options)
{
}
#region system sets
public DbSet<ServerSetting> Settings { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<SecurityItem> SecurityItems { get; set; }
public DbSet<UserSession> UserSessions { get; set; }
public DbSet<SecurityRight> SecurityRights { get; set; }
public DbSet<SecurityOrgGroup> SecurityOrgGroups { get; set; }
public DbSet<SecurityPrivilege> Privileges { get; set; }
#endregion
#region Core sets
public DbSet<Tournament> Tournaments { get; set; }
public DbSet<TournamentSetting> TournamentSettings { get; set; }
public DbSet<Club> Clubs { get; set; }
public DbSet<Team> Teams { get; set; }
public DbSet<TournamentClass> Classes { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<MatchSet> MatchSets { get; set; }
#endregion
#region global sets
public DbSet<GeoPoint> GeoPositions { get; set; }
public DbSet<Country> Countries { get; set; }
#endregion
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<UserRole>()
.HasKey(t => new { t.UserId, t.RoleId });
builder.Entity<UserRole>()
.HasOne(ur => ur.User)
.WithMany(l => l.UserRoles)
.HasForeignKey(ur => ur.UserId);
builder.Entity<UserRole>()
.HasOne(ur => ur.Role)
.WithMany(l => l.UserRoles)
.HasForeignKey(ur => ur.RoleId);
builder.Entity<ItemRight>()
.HasKey(t => new {t.SecurityItemId, t.SecurityRightId});
}
}
我的播种机代码:
public static class DbContextExtension
{
public static bool AllMigrationsApplied(this DbContext context)
{
var applied = context.GetService<IHistoryRepository>()
.GetAppliedMigrations()
.Select(m => m.MigrationId);
var total = context.GetService<IMigrationsAssembly>()
.Migrations
.Select(m => m.Key);
return !total.Except(applied).Any();
}
public static void EnsureSeeded(this TMContext context)
{
#region users
//add admin user
if (!context.Users.Any())
{
User admin = new User
{
UserName = "admin",
FirstName = "Admin",
LastName = "User",
Email = "mail@email.org",
};
admin.CreatedBy = admin.Id;
admin.SetPassword("admin");
context.Users.Add(admin);
context.SaveChanges();
}
Guid adminId = context.Users.First(x => x.UserName == "admin").Id;
#endregion
#region server settings
//server settings
if (!context.Settings.Any())
{
context.Settings.Add(new ServerSetting
{
Key = "ServerType",
Section = "Public",
SortOrder = 0,
TargetDataType = "System.String",
Value = "TMLocalServer"
});
context.Settings.Add(new ServerSetting
{
Key = "Instance",
Section = "Public",
SortOrder = 1,
TargetDataType = "System.Guid",
Value = Guid.NewGuid().ToString()
});
context.SaveChanges();
}
#endregion
#region security rights
//security rights
if (!context.SecurityRights.Any())
{
context.SecurityRights.Add(new SecurityRight { Name = "Read", CreatedBy = adminId });
context.SecurityRights.Add(new SecurityRight { Name = "Insert", CreatedBy = adminId });
context.SecurityRights.Add(new SecurityRight { Name = "Update", CreatedBy = adminId });
context.SecurityRights.Add(new SecurityRight { Name = "Delete", CreatedBy = adminId });
context.SaveChanges();
}
#endregion
#region org groups
//org groups
if (!context.SecurityOrgGroups.Any())
{
#region security groups
context.SecurityOrgGroups.Add(new SecurityOrgGroup
{
ReadableId = "SecurityManagement",
ParentId = null,
Text = "Security Management",
Description = "All seetings concerning basic security",
CreatedBy = adminId
});
context.SaveChanges();
#endregion
context.SecurityOrgGroups.Add(new SecurityOrgGroup
{
ReadableId = "MasterFiles",
ParentId = null,
Text = "Master Files",
Description = "Management of the Master Files for the application",
CreatedBy = adminId
});
#region operations
context.SecurityOrgGroups.Add(new SecurityOrgGroup
{
ReadableId = "Operations",
ParentId = null,
Text = "Operations",
Description = "Security settings for operations functions",
CreatedBy = adminId
});
context.SaveChanges();
#endregion
}
#endregion
#region security items
//security items
if (!context.SecurityItems.Any())
{
SecurityItem item = new SecurityItem { ReadableId = "UserManagement", Name = "User Management", Description = "User management and role membership", CreatedBy = adminId };
AddItemToGroup(context, "SecurityManagement", item);
AddAvailableRights(context, item, new List<string> { "Read", "Insert", "Update", "Delete" });
context.SecurityItems.Add(item);
item = new SecurityItem { ReadableId = "RoleManagement", Name = "Role Management", Description = "Manage roles and their configuration", CreatedBy = adminId };
AddItemToGroup(context, "SecurityManagement", item);
AddAvailableRights(context, item, new List<string> { "Read", "Insert", "Update", "Delete" });
context.SecurityItems.Add(item);
context.SaveChanges();
item = new SecurityItem { ReadableId = "CountryManagement", Name = "Country Management", Description = "Manage list of countries", CreatedBy = adminId };
AddItemToGroup(context, "MasterFiles", item);
AddAvailableRights(context, item, new List<string> { "Read", "Insert", "Update", "Delete" });
context.SecurityItems.Add(item);
context.SaveChanges();
}
#endregion
#region security roles
//security roles
if (!context.Roles.Any())
{
context.Roles.Add(new Role
{
ReadableId = "SysAdmin",
Name = "System Administrator",
Description = "Users can do everything",
CreatedBy = adminId
});
context.SaveChanges();
AddUserToRoles(context, "admin", new List<string> { "SysAdmin" });
AddPrivilegesToRole(context, "SysAdmin", "UserManagement", new List<string> { "Read", "Insert", "Update", "Delete" });
AddPrivilegesToRole(context, "SysAdmin", "RoleManagement", new List<string> { "Read", "Insert", "Update", "Delete" });
AddPrivilegesToRole(context, "SysAdmin", "CountryManagement", new List<string> { "Read", "Insert", "Update", "Delete" });
context.SaveChanges();
}
#endregion
}
#region security helpers
private static void AddAvailableRights(TMContext dbcontext, SecurityItem item, List<string> rights)
{
foreach (string right in rights)
{
var r = dbcontext.SecurityRights.FirstOrDefault(x => x.Name == right);
if (r != null)
{
ItemRight ir = new ItemRight { SecurityItemId = item.Id, SecurityRightId = r.Id };
item.ItemRights.Add(ir);
}
}
}
private static void AddPrivilegesToRole(TMContext dbcontext, string roleid, string itemid, List<string> rights)
{
SecurityItem item = dbcontext.SecurityItems.FirstOrDefault(x => x.ReadableId == itemid);
Role role = dbcontext.Roles.FirstOrDefault(x => x.ReadableId == roleid);
if (item != null && role != null)
foreach (string right in rights)
{
var r = dbcontext.SecurityRights.FirstOrDefault(x => x.Name == right);
if (r != null)
{
SecurityPrivilege privilege = new SecurityPrivilege { CreatedBy = item.CreatedBy, SecurityItemId = item.Id, SecurityRightId = r.Id, RoleId = role.Id, SortOrder = rights.IndexOf(right)};
role.Privileges.Add(privilege);
}
}
}
private static void AddItemToGroup(TMContext dbcontext, string groupid, SecurityItem item)
{
SecurityOrgGroup group = dbcontext.SecurityOrgGroups.FirstOrDefault(x => x.ReadableId == groupid);
if (group != null)
item.OrgGroupId = group.Id;
}
private static void AddOrgGroupToParent(TMContext dbcontext, string parentid, SecurityOrgGroup newgroup)
{
SecurityOrgGroup parent = dbcontext.SecurityOrgGroups.FirstOrDefault(x => x.ReadableId == parentid);
if (parent != null)
{
newgroup.ParentId = parent.Id;
dbcontext.SecurityOrgGroups.Add(newgroup);
}
}
private static void AddUserToRoles(TMContext dbcontext, string username, List<string> roles)
{
User user = dbcontext.Users.FirstOrDefault(x => x.UserName == username);
if (user != null)
{
foreach (string readablerole in roles)
{
Role role = dbcontext.Roles.FirstOrDefault(x => x.ReadableId == readablerole);
if (role != null)
user.UserRoles.Add(new UserRole { User = user, Role = role });
}
}
}
private static void AssignRightsToItem()
{
}
#endregion
}
非常感谢任何关于我所缺少的想法。
ragards
汉斯的Henrik
答案 0 :(得分:1)
我无法在代码中看到任何错误。播种或request.UserName包含不存在的用户名时可能存在问题。
如果您考虑以下播种代码(稍微适合您的实体):
var users = new User[]
{
new User{ Id = Guid.NewGuid(), FirstName= "Bob", LastName ="b", UserName = "bob" },
new User{ Id = Guid.NewGuid(), FirstName= "Alice", LastName ="a", UserName = "alice" }
};
var roles = new Role[]
{
new Role{ Id = Guid.NewGuid(), CreatedBy = users[0].Id, Name = "role1", ReadableId="role1" },
new Role{ Id = Guid.NewGuid(), CreatedBy = users[0].Id, Name = "role2", ReadableId="role2" }
};
_context.Users.AddRange(users);
_context.Roles.AddRange(roles);
_context.SaveChanges();
var userroles = new UserRole[]
{
new UserRole{ User = users[0], Role = roles[0] },
new UserRole{ User = users[0], Role = roles[1] }, //bob is assigned 2 roles
new UserRole{ User = users[1], Role = roles[1] },
};
您稍后会调用以下方法:
var user = _context.Users.Include(x => x.UserRoles).FirstOrDefault(u => u.UserName == "bob");
然后用户将包含2个UserRoles。在观察窗口中验证:
==编辑==
您说UserRoles的Role属性等于null
。您需要使用ThenInclude()
扩展方法来包含这些内容。此方法允许您包含更深层次的导航属性,如下所示:
var user = _context.Users
.Include(u => u.UserRoles)
.ThenInclude(ur => ur.Role)
.FirstOrDefault(u => u.UserName == "bob");