Sto cercando di lavorare con relazioni molti-a-molti nella mia applicazione web. Sto usando un codice base di repository generico.
Ecco le mie entità
public class UserEntity : BaseEntity<int>
{
public string EmployeeId { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public virtual ICollection<UserRoleEntity> UserRoles { get; set; }
}
public class RoleEntity : BaseEntity<int>
{
public string Name { get; set; }
public virtual ICollection<UserRoleEntity> Users { get; set; }
}
public class UserRoleEntity : BaseEntity<Guid>
{
public int UserId { get; set; }
public int RoleId { get; set; }
public virtual UserEntity UserEntity { get; set; }
public virtual RoleEntity RoleEntity { get; set; }
}
Questa è la configurazione del modello di contesto
private void ConfigureUserRole(EntityTypeBuilder<UserRoleEntity> builder)
{
builder.ToTable("UserRole");
//there is no need for a surrogate key on many-to-many mapping table
builder.Ignore("Id");
builder.HasKey(ur => new { ur.RoleId, ur.UserId });
builder.HasOne(ur => ur.RoleEntity)
.WithMany(r => r.Users)
.HasForeignKey(ur => ur.RoleId);
builder.HasOne(ur => ur.UserEntity)
.WithMany(u => u.UserRoles)
.HasForeignKey(ur => ur.UserId);
}
Questo è il metodo get principale del mio repository generico (in realtà è l' implementazione di Chris Pratt ). Si noti la riga query.Include
, i metodi get del repository generico fanno uso di Include
api di EF Core per ottenere un'entità dipendente che viene come stringa parametro.
protected virtual IQueryable<T> GetQueryable(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
string includeProperties = null,
int? skip = null,
int? take = null)
{
includeProperties = includeProperties ?? string.Empty;
IQueryable<T> query = _dbContext.Set<T>();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
query = orderBy(query);
}
if (skip.HasValue)
{
query = query.Skip(skip.Value);
}
if (take.HasValue)
{
query = query.Take(take.Value);
}
return query;
}
E nel mio servizio, voglio ottenere i dati dell'utente con i suoi dipendenti a pieno titolo.
public class UserService : IUserService
{
private IRepository<UserEntity> _userRepository;
private IRepository<RoleEntity> _roleRepository;
public UserService(IRepository<UserEntity> userRepository, IRepository<RoleEntity> roleRepository)
{
_userRepository = userRepository;
_roleRepository = roleRepository;
}
public UserEntity GetUserData(string employeeId)
{
var user = _userRepository.GetFirst(u => u.EmployeeId == employeeId, includeProperties: "UserRoles");
//var roles = _roleRepository.GetAll().ToList();
return user;
}
}
Quando si esegue il codice di servizio sopra riportato, ottengo l'utente con il suo UserRole
dipendente, tuttavia, quando controllo il UserRole
di RoleEntity
cui ho bisogno, è null
.
Come posso ottenere i dati RoleEntity
dipendenti semplicemente modificando il metodo get del repository generico?
In secondo luogo, la riga commentata nel codice di servizio ( _roleRepository.GetAll()
), quando viene anche eseguita, RoleEntity
viene immediatamente riempita con il suo valore corretto. Come sta succedendo?
Il percorso include solo un hop da UserEntity
a UserRoleEntity
(tramite la proprietà UserRoles
. È necessario includere il passaggio successivo per assicurarsi di acquisire anche RoleEntity
. Per fare ciò, modificare il percorso in UserRoles.RoleEntity
, ad esempio:
var user = _userRepository.GetFirst(
u => u.EmployeeId == employeeId,
includeProperties: "UserRoles.RoleEntity");