I am configuring identity user, I have seeded users with roles
by many to many relationship as follows:
public class AppUser : IdentityUser
{
public string DisplayName { get; set;}
public ICollection<AppUserRole> UserRoles { get; set;}
}
public class AppRole : IdentityRole
{
public ICollection<AppUserRole> UserRoles { get; set; }
}
public class AppUserRole : IdentityUserRole<string>
{
public AppUser User { get; set; }
public AppRole Role { get; set; }
}
builder.Entity<AppUser>()
.HasMany(ur => ur.UserRoles)
.WithOne(u => u.User)
.HasForeignKey(ur => ur.UserId)
.IsRequired();
builder.Entity<AppRole>()
.HasMany(ur => ur.UserRoles)
.WithOne(u => u.Role)
.HasForeignKey(ur => ur.RoleId)
.IsRequired();
In the screenshot - why am I getting the shadow id UserId1, RoleId1?
I am trying to get all user with their respective roles or roles
public UsersController(UserManager<AppUser> userManager)
{
_userManager = userManager;
}
public async Task<ActionResult> GetUsersWithRoles()
{
var users = await _userManager.Users
.Include(r => r.UserRoles)
.ThenInclude(r => r.Role)
// .OrderBy(u => u.UserName)
.Select(u => new
{
// u.Id,
Username = u.UserName,
DisplayName = u.DisplayName,
Role = u.UserRoles.Select(r => r.Role.Name).ToList()
})
.ToListAsync();
return Ok(users);
}
I am getting the users with empty role array... but I think this code should work
i think you should add it in AppUserRole
builder.HasKey(a => new { a.UserId, a.RoleId });
then this is ideal dto
public class DtoSelectedUsersAdmin
{
public string UserName { get; set; }
public string Password { get; set; }
public string Gender { get; set; }
public int Age { get; set; }
public int AppRoleId { get; set; }
public string AppRoleName { get; set; }
public virtual ICollection<AppUserRole> AppRole { get; set; }
public override void CustomMappings(IMappingExpression<AppUser, DtoSelectedUsersAdmin> mapping)
{
.ForMember(a => a.AppRoleName, s => s.MapFrom(q => q.Roles.FirstOrDefault().AppRole.Name))
.ForMember(a => a.AppRoleId, s => s.MapFrom(q => q.Roles.FirstOrDefault().AppRole.Id));
}
}
and finally service class to get all users with their role
public async Task<List<DtoSelectedUsersAdmin>> GetAllUsersWithRolesAsync()
{
var result = await Users.Select(user => new DtoSelectedUsersAdmin
{
Id = user.Id,
AppRole = user.Roles,
UserName = user.UserName
}).ToListAsync();
return result;
}
Related
My original code:
public static User GetUser(int userID)
{
_context.Users.Where(x => x.UserId == userID)
.FirstOrDefault();
}
Here user.usergovernments is null.
New code:
public static User GetUser(int userID)
{
using (var _context = new SafetyContext())
{
// find lga for this user
var user_govs = from o in _context.Users
join i in _context.UserGovernments
on o.UserId equals i.UserId
where o.UserId == userID
select new { o, i };
var user = _context.Users
.Where(x => x.UserId == userID)
.FirstOrDefault();
foreach (var lga in user_govs)
{
user.UserGovernments.Add(new UserGovernment { UserId = userID, UserGovernmentId = lga.i.UserGovernmentId, LocalGovId = lga.i.LocalGovId, StateId = lga.i.StateId });
}
return user;
}
}
This time I get duplicate usergovernment records! One is loaded and the other is the one I added!
Model classes:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public UserAccess AccessLevel { get; set; }
public ICollection<UserGovernment> UserGovernments { get; set; }
}
public class UserGovernment
{
public int UserGovernmentId { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public int StateId { get; set; }
public State State { get; set; }
public int LocalGovId { get; set; }
public LocalGov LocalGov { get; set; }
}
public class LocalGov
{
public int LocalGovId { get; set; }
public string Name { get; set; }
public string LgaPid { get; set; }
public ICollection<UserGovernment> UserGovernments { get; set; }
}
Context:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserGovernment>()
.HasKey(bc => new {bc.UserGovernmentId});
modelBuilder.Entity<UserGovernment>()
.HasOne(bc => bc.User)
.WithMany(b => b.UserGovernments)
.HasForeignKey(bc => bc.UserId);
modelBuilder.Entity<UserGovernment>()
.HasOne(bc => bc.LocalGov)
.WithMany(c => c.UserGovernments)
.HasForeignKey(bc => bc.LocalGovId);
}
What am I doing wrong?
LocalGov and User are individual entities while UserGovernments is the many-to-many joining table/entity
Write Query as like bellow.
Include method fill your UserGovermnet property automaticaly according to it's matched userId
_context.Users.Where(x => x.UserId == userID)
.Include(u=>u.UserGoverments)
.FirstOrDefault();
I have the following one-to-one relationship with ApplicationUser:
public class Person
{
public Guid PersonId { get; set; }
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public string Role { get; set; }
public string Country { get; set; }
public DateTime CreatedDate { get; set; }
public bool IsActive { get; set; }
public ApplicationUser User { get; set; }
}
public class ApplicationUser : IdentityUser
{
public Guid PersonId { get; set; }
public string Provider { get; set; } = "LOCAL";
public string ExternalUserId { get; set; }
public Person Person { get; set; }
}
DbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> opts) : base(opts) { }
public DbSet<Person> Person { get; set; }
public DbSet<ApplicationUser> User { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new PersonConfiguration());
modelBuilder.Entity<ApplicationUser>(e => {
e.ToTable(name: "User");
e.HasOne(p => p.Person).WithOne(u => u.User);
//e.HasOne(p => p.Person).WithOne().HasForeignKey;
});
modelBuilder.Entity<IdentityRole>(e => e.ToTable(name: "Role"));
modelBuilder.Entity<IdentityUserRole<string>>(e => e.ToTable(name: "UserRole"));
modelBuilder.Entity<IdentityUserClaim<string>>(e => e.ToTable(name: "UserClaim"));
modelBuilder.Entity<IdentityUserLogin<string>>(e => e.ToTable(name: "UserLogin"));
modelBuilder.Entity<IdentityUserToken<string>>(e => e.ToTable(name: "UserToken"));
modelBuilder.Entity<IdentityRoleClaim<string>>(e => e.ToTable(name: "RoleClaim"));
}
}
Person entity configuration:
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.ToTable("Person");
builder.HasOne(u => u.User)
.WithOne(p => p.Person)
.HasForeignKey<Person>(p => p.UserId);
}
}
The problem is when I get the person data from db the related user returns null even using the Include extension.
FYI: I've tried to load the users from db using the dbcontext but it returns null too.
I tested your code,I think there is no problem with your configuration,so,the issue may caused by your data insert.You can try to add a new Person and try to find them like bellow:
var user = new ApplicationUser
{
Email = "www.example.com"
};
var p = new Person
{
FirstName = "AA",
//...
User = user,
};
_context.Persons.Add(p);
_context.SaveChanges();
var u = _context.User.ToList();
var pe = _context.Persons.Include(c => c.User).ToList();
Im trying to save a new user into the users table with a new role. Here's the model and configuration.
When I insert the below entity, The role table gets populated with the new role, but the user entity is not being inserted.
`var userEntity = new User
{
Id = 0,
Active = true,
Firstname = "Fname",
Lastname = "Lname",
Password = "test",
Phonenumber = "2223334444",
Test = false,
Username = "test#test.com",
RoleId = 0
// Role = roleEntity
};
var roleEntity = new Role
{
Id = 0,
Name = "test role",
Active = true,
Users = new List<User>
{
userEntity
}
};
context.Role.Add(roleEntity);
await context.SaveChangesAsync();
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Firstname { get; set; }
public string Middlename { get; set; }
public string Lastname { get; set; }
public string Phonenumber { get; set; }
public bool Active { get; set; }
public bool Test { get; set; }
public int RoleId { get; set; }
public virtual Role Role { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public virtual ICollection<User> Users { get; set; }
public Role()
{
Users = new HashSet<User>();
}
}`
Here are the entity configurations.
`
public class RoleConfiguration : IEntityTypeConfiguration<Role>
{
public void Configure(EntityTypeBuilder<Role> builder)
{
builder.ToTable("Role");
builder.HasKey(r => r.Id);
builder.Property(r => r.Id).IsRequired().ValueGeneratedOnAdd();
builder.Property(r => r.Name).IsRequired().HasMaxLength(255);
builder.Property(r => r.Active).IsRequired();
builder.HasMany(r => r.Users)
.WithOne(u => u.Role)
.HasForeignKey(u => u.RoleId)
.OnDelete(DeleteBehavior.Restrict);
}
}
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("User");
builder.HasKey(u => u.Id);
builder.Property(u => u.Id).IsRequired().ValueGeneratedOnAdd();
builder.Property(u => u.Username).IsRequired().HasMaxLength(255);
builder.Property(u => u.Password).IsRequired();
builder.Property(u => u.Firstname).IsRequired().HasMaxLength(255);
builder.Property(u => u.Lastname).IsRequired().HasMaxLength(255);
builder.Property(u => u.Phonenumber).HasMaxLength(255);
builder.Property(u => u.Active).IsRequired();
builder.Property(u => u.Test).IsRequired();
builder.Property(u => u.RoleId).IsRequired();
builder.HasOne(u => u.Role)
.WithMany(r => r.Users)
.HasForeignKey(u => u.RoleId)
.OnDelete(DeleteBehavior.Restrict);
}
}`
Is there anything I'm doing wrong.
Thanks for your help.
I made a mistake by using
context.Entry(entity).State = EntityState.Added;
instead of
context.Add(entity);
that's why the related entities weren't being added.
I'm having issues using Entity Framework (6.3) to retrieve a child collection of entities where the relationship uses a composite key. In the example below I'm trying to get the Sprints associated with a Plan, but the Sprints child collection keeps coming back empty.
// Returns no sprints
var queryUsingSelect = await _dbContext
.Plans
.Select(p => new
{
p,
p.Sprints
})
.ToListAsync();
// Returns a plan without sprints
var queryUsingInclude = await _dbContext
.Plans
.Include(p => p.Sprints)
.ToListAsync();
// Returns me all sprints
var allSprints = await _dbContext
.Plans
.SelectMany(p => p.Sprints)
.ToListAsync();
In the last query I've tested it using SelectMany which does return Sprints, but really I need to be able to do it using Include. I'm having the same issue with another collection in the same project so it seems to be an issue with my approach in general. Note that I have lazy loading turned off to prevent accidental n+1 queries.
Here's a stripped down version of my code:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
}
public class Aspiration
{
public int AspirationId { get; set; }
public string Title { get; set; }
}
public class Plan
{
public Plan()
{
Sprints = new List<Sprint>();
}
public int UserId { get; set; }
public int AspirationId { get; set; }
public virtual User User { get; set; }
public virtual Aspiration Aspiration { get; set; }
public virtual ICollection<Sprint> Sprints { get; set; }
}
public class Sprint
{
public int SprintId { get; set; }
public int UserId { get; set; }
public int AspirationId { get; set; }
public virtual Plan Plan { get; set; }
public virtual User User { get; set; }
public virtual Aspiration Aspiration { get; set; }
}
public class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
Property(t => t.Name)
.HasMaxLength(100)
.IsRequired();
}
}
public class AspirationMap : EntityTypeConfiguration<Aspiration>
{
public AspirationMap()
{
Property(t => t.Title)
.HasMaxLength(100)
.IsRequired();
}
}
public class PlanMap : EntityTypeConfiguration<Plan>
{
public PlanMap()
{
HasKey(s => new { s.UserId, s.AspirationId });
HasRequired(s => s.User)
.WithMany()
.HasForeignKey(s => s.UserId);
HasRequired(s => s.Aspiration)
.WithMany()
.HasForeignKey(s => s.AspirationId);
}
}
public class SprintMap : EntityTypeConfiguration<Sprint>
{
public SprintMap()
{
HasRequired(s => s.User)
.WithMany()
.HasForeignKey(s => s.UserId);
HasRequired(s => s.Aspiration)
.WithMany()
.HasForeignKey(s => s.AspirationId);
HasRequired(s => s.Plan)
.WithMany(d => d.Sprints)
.HasForeignKey(s => new { s.AspirationId, s.UserId });
}
}
public class MyDbContext : DbContext
{
static MyDbContext()
{
Database.SetInitializer<MyDbContext>(null);
}
public MyDbContext()
: base(DbConstants.ConnectionStringName)
{
Configuration.LazyLoadingEnabled = false;
}
public DbSet<User> Users { get; set; }
public DbSet<Aspiration> Aspirations { get; set; }
public DbSet<Plan> Plans { get; set; }
public DbSet<Sprint> Sprints { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder
.Map(new UserMap())
.Map(new AspirationMap())
.Map(new PlanMap())
.Map(new SprintMap())
;
}
}
Well, I see some errors in your mapping.
The FK of Plan in Sprint must have the same order of the PK of Plan. So replace this:
HasRequired(s => s.Plan)
.WithMany(d => d.Sprints)
.HasForeignKey(s => new { s.AspirationId,s.UserId });
for this:
HasRequired(s => s.Plan)
.WithMany(d => d.Sprints)
.HasForeignKey(s => new { s.UserId, s.AspirationId });
After making those changes, I tried to run your code and everything worked fine.
I have a problem when selecting a User.
public class UserMap : EntityTypeConfiguration<User>
{
public UserMap ()
{
ToTable("USERS");
HasKey(e => e.Id);
Property(e => e.Id).HasColumnName("ID");
Property(e => e.Name).HasColumnName("NAME");
Property(e => e.Password).HasColumnName("PASSWORD");
Property(e => e.Date).HasColumnName("DATE");
Property(e => e.Token).HasColumnName("TOKEN");
Property(e => e.Active).HasColumnName("ACTIVE");
HasRequired(e => e.Company).WithMany().Map(e => e.MapKey("COMPANY_ID"));
HasMany(e => e.BranchesUsers).WithRequired().Map(e => e.MapKey("USER_ID"));
}
}
public class BranchMap : EntityTypeConfiguration<Branch>
{
public BranchMap ()
{
ToTable("BRANCHES");
HasKey(e => e.Id);
Property(e => e.Id).HasColumnName("ID");
Property(e => e.Name).HasColumnName("NAME");
Property(e => e.Date).HasColumnName("DATE");
Property(e => e.Active).HasColumnName("ACTIVE");
HasRequired(e => e.Company).WithMany().Map(e => e.MapKey("COMPANY_ID"));
HasMany(e => e.UsersBranches).WithRequired().Map(e => e.MapKey("BRANCH_ID"));
}
}
public class UserBranchMap : EntityTypeConfiguration<UserBranch>
{
public UserBranchMap()
{
ToTable("USERS_BRANCHES");
HasKey(e => e.Id);
Property(e => e.Id).HasColumnName("ID");
HasOptional(e => e.User).WithMany().Map(e => e.MapKey("USER_ID"));
HasOptional(e => e.Profile).WithMany().Map(e => e.MapKey("PROFILE_ID"));
HasOptional(e => e.Branch).WithMany().Map(e => e.MapKey("BRANCH_ID"));
HasOptional(e => e.Company).WithMany().Map(e => e.MapKey("COMPANY_ID"));
}
}
this is my model:
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public DateTime Date { get; set; }
public string Token { get; set; }
public Company Company { get; set; }
public List<UserBranch> BranchesUsers{ get; set; }
public bool Active{ get; set; }
}
public class Branch
{
public long Id { get; set; }
public Company Company{ get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
public List<UserBranch> UsersBranches { get; set; }
public bool Active { get; set; }
}
public class UserBranch
{
public long Id { get; set; }
public User User { get; set; }
public Profile Profile { get; set; }
public Branch Branch { get; set; }
public Company Company { get; set; }
}
when I perform a simple select the user model I get this error:
One or more validation errors were detected during model generation:
USER_ID: Name: Each property name in a type must be unique. Property name 'USER_ID' is already defined.
BRANCH_ID: Name: Each property name in a type must be unique. Property name 'BRANCH_ID' is already defined.