Many to many - jak zrobić poprawnie select

0

Mam takie klasy:

CoreRole

    public class  CoreRole
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public ICollection<CoreUserRole> UserRole { get; set; }
    }

CoreUser

    public class CoreUser
    {
        public int Id { set; get; }
        public string Login { set; get; }
        public string Password { set; get; }
        public bool IsDelete { set; get; }
        public ICollection<CoreUserRole> UserRole { get; set; }
    }

CoreUserRole

    public class CoreUserRole
    {
        public int UserId { get; set; }
        public CoreUser User { get; set; }
        public int RoleId { get; set; }
        public CoreRole Role { get; set; }
    }

CoreDataContext

    public class CoreDataContext : DbContext
    {
        public DbSet<CoreUser> Users { get; set; }
        public DbSet<CoreRole> Roles { get; set; }
        public DbSet<CoreUserRole> UsersRoles { get; set; }
        
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<CoreUserRole>()
                .HasKey(ur => new { ur.RoleId, ur.UserId });
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseMySql(@"Server=localhost;database=chat;uid=root;pwd=haslo;port=3307");
            
        }
    }

Zapytanie do poprawy:

            var query = from u in ctx.Users
                select new CoreUser
                {
                    Id = u.Id,
                    IsDelete = u.IsDelete,
                    Login = u.Login,
                    UserRole = from r in ctx.Roles
                        join ur in ctx.UsersRoles on r.Id equals ur.RoleId
                        where ur.UserId == u.Id
                        select new CoreUserRole { Role = r }
                };
    
            var res = query.ToList();

Docelowo chciałbym żeby była pobrana lista użytkowników wraz z listą ról, które ten użytkownik posiada.

Błąd, który pojawia się:

UserRepository.cs(83, 32): [CS0266] Nie można niejawnie przekonwertować typu „System.Linq.IQueryable<App.Modules.Core.Models.CoreUserRole>” na „System.Collections.Generic.ICollection<App.Modules.Core.Models.CoreUserRole>”. Istnieje konwersja jawna (czy nie brakuje rzutu?).

Ps. wiem co mówi komunikat, ale nadal nie wiem jak "przekonwertować typ" - zapytanie.

Proszę o pomoc :-)

1

A nie lepiej byłoby zrobić var usersWithRoles=ctx.Users.Include(r=>r.UserRole).ToList();
Przy każdym userze masz jego liste ról. Nie sprawdzałem ale powinno działaś.

0

Jakiekolwiek proste rozwiązanie będzie w porządku. Jednak to co podałaś to nie wiąże "UserRole" z modelem "Role"

Poniżej zamieszczam wynik tego kodu:

{
   "result":[
      {
         "id":1,
         "login":"Happy",
         "password":null,
         "isDelete":false,
         "userRole":[
            {
               "userId":1,
               "roleId":1,
               "role":null
            }
        }
    ]
}
0

Nie sprawdzałem czy to przejdzie ale może jakiś ToList() po podzapytaniu o UserRoles bo cjyba nie może zmaterializowac UserRoles w podzapytaniu.

3

A jaki jest w ogóle sens istnienia CoreUserRole? Skoro nie zawiera żadnych dodatkowych pól, to nie ma sensu, aby była elementem modelu.

CoreRole

    public class  CoreRole
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public ICollection<CoreUser> Users { get; set; }
    }

CoreUser

    public class CoreUser
    {
        public int Id { set; get; }
        public string Login { set; get; }
        public string Password { set; get; }
        public bool IsDelete { set; get; }
        public ICollection<CoreRole> Roles { get; set; }
    }

I to wszystko. A zapytanie to po prostu: var res = ctx.Users.Include(x => x.Roles).Where(...).ToList();

A jeśli w tabeli złączeniowej chcesz mieć dodatkowe pola, to nie masz już many to many tylko dwa razy one to many - tak przynajmniej traktuje to EF, więc Ty także powinieneś budować zapytania w taki sposób. Bez projekcji do nowej klasy się chyba nie obędzie:

var usersWithRoles = ctx.Users
    .Select(x => new
    {
        User = x,
        Roles = x.UserRoles.Select(ur => ur.Role)
    })
    .ToList();
0

Skoro to jest EF Core to można jeszcze zrobić taką konstrukcję: var usersWithRoles=ctx.Users.Include(r=>r.UserRole).ThenInclude(ur=>ur.Role).ToList();
Niech Cie nie zmyli że ThenInclude nie ma w Intelisense. Ale po napisaniu kompiluje się i działa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1