-1

What I'm trying to do is to is join tables to fill a viewModel that looks like this:

public class UserViewModel
{
    public String Id { get; set; }
    public String UserName { get; set; }
    public String Email { get; set; }
    public String Role { get; set; }
}

My query atm looks like this, but it doesn't work obviously, but it might help with descriping the problem.

public IActionResult AddAdmin()
{
    var allUsers = (from u in _dbContext.Users
                    join r in _dbContext.UserRoles on u.Id equals r.UserId
                    join i in _dbContext.Roles on r.RoleId equals i.Id
                    select new UserViewModel
                 {
                     UserName = u.UserName,
                     Email = u.Email,
                     Id = u.Id,
                     Role = i.Name
                 }).ToList();

    return View(allUsers);
}

As you see the thing I find hard is to apply the role to the viewModel, since they are connected to eachother with a manyTomany Table

Problem: The query does not work, and does not give anything in result Before I joined the role into the viewModel, i got the data to the view, now i get nothing at all.

My Question: What's the correct way to do this? To easily navigate through the data

LittleMygler
  • 632
  • 10
  • 24
  • 4
    Use relations and navigation properties, *not* hard-coded joins. It's the job of the ORM to generate the joins. Your `User` entity should contain a `UserRoles` property that contains `Roles` – Panagiotis Kanavos Sep 11 '18 at 13:13
  • Can you elaborate? How would that look like code-wise? – LittleMygler Sep 11 '18 at 13:14
  • 1
    start from any EF Core tutorial. All of them contain a section where they show how to configure relations. There are *many* duplicates as well. – Panagiotis Kanavos Sep 11 '18 at 13:15
  • 1
    I'm unclear on what exactly is wrong with you're current query. Is it that you get multiple models for the same user and different roles? If so it seems like your model needs to change to allow for multiple roles. – juharr Sep 11 '18 at 13:17
  • I agree with @juharr. Rather than a duplicate is not clear at all what's wrong here – Camilo Terevinto Sep 11 '18 at 13:17
  • The data has been automaticly generated by Identity, all I'm trying to do is to navigate through the data is has saved. – LittleMygler Sep 11 '18 at 13:18
  • @PanagiotisKanavos I agree that using a fluent API would be better here, but I'm not sure how that solves whatever the issues is. Doing joins with Linq is messy and should be unnecessary, but should still get the job done. – juharr Sep 11 '18 at 13:20
  • What would you have done @juharr? – LittleMygler Sep 11 '18 at 13:21
  • 1
    @juharr no it won't. It's not about a Fluent API, it's about configuring the relations and context. What's the point of using EF or any ORM if one ends up *joining* ? – Panagiotis Kanavos Sep 11 '18 at 13:21
  • Have you tried running queries on your DB to see what data is there? Try creating the equivalent query in SQL to see what results you get. – juharr Sep 11 '18 at 13:21
  • @Charlie It's not clear why your current code does not work or what is wrong with it. Can you explain a little more? – Camilo Terevinto Sep 11 '18 at 13:21
  • I updated the question – LittleMygler Sep 11 '18 at 13:23
  • @PanagiotisKanavos I'm not disagreeing with that, but if the data isn't in the DB it still wouldn't work. Do you think those joins are not the equivalent of what you'd get with navigation properties? – juharr Sep 11 '18 at 13:23
  • @Charlie And you say you have a User, a Role and a UserRole in your database in such a way that the INNER JOINs in your code should actually return data? – Camilo Terevinto Sep 11 '18 at 13:25
  • @juharr why use an ORM then? This isn't a LINQ to Objects question, this is an attempt to use SQL inside C#. There's no point in using EF in that case, in fact it can create a *lot* of problems as EF tries to do its job and translate the LINQ query to SQL. It would be better to use Dapper or any other tool that allows a raw SQL query and mapping to results. – Panagiotis Kanavos Sep 11 '18 at 13:25
  • @CamiloTerevinto Yes exactly, I have a User table, that is connected to UserRoles that is connected to Roles. All automatically generated, not by me. But by Identity – LittleMygler Sep 11 '18 at 13:26
  • @Charlie Yes, I know those are Identity's tables. I asked whether you inserted a User, a Role and a map between those. Can you share the results of such query? – Camilo Terevinto Sep 11 '18 at 13:28
  • @PanagiotisKanavos All I'm saying is that I don't see how changing this query that uses joins to use navigation properties would end up in SQL that would give different results. And as I said before I 100% agree that people need to stop with the join and use navigation properties. It's a great suggestion. I just don't see it fixing whatever the problem is. – juharr Sep 11 '18 at 13:28
  • @juharr With EF Core (as it is currently) one never knows - see for instance https://stackoverflow.com/questions/52246852/entity-framework-core-sqlite-groupjoin-after-join-flattens-results, wrong query with manual joins, good when using navigation properties (not shown there). Most likely that's not the case here, but just to let you know :) – Ivan Stoev Sep 11 '18 at 13:33
  • @CamiloTerevinto If you're wondering if I have data in the database, yes I have. It works if i remove the role joins, also I can see it in the SQL management studio – LittleMygler Sep 11 '18 at 13:34
  • @Charlie Are you sure the database contains data? e.g. if you do `var users = _dbContext.Users.ToList(); var userRoles = _dbContext.UserRoles.ToList(); var roles = _dbContext.Roles.ToList();`, are all these lists non empty? – Ivan Stoev Sep 11 '18 at 13:36
  • @IvanStoev yes I'm sure, just did it and user.count is 1 and roles is 2 – LittleMygler Sep 11 '18 at 13:39

2 Answers2

0

When I did it like this, it worked...

public IActionResult AddAdmin()
{
    var allUsers = (from u in _dbContext.Users
                    select new UserViewModel
                 {
                     UserName = u.UserName,
                     Email = u.Email,
                     Id = u.Id

                 }).ToList();

    foreach (var item in allUsers)
    {
        var roleId = _dbContext.UserRoles.Where(x => x.UserId == item.Id).FirstOrDefault();
        item.Role = _dbContext.Roles.Where(x => x.Id == roleId.RoleId).FirstOrDefault().Name;
    }
    return View(allUsers);
}

I know it looks like s***..

LittleMygler
  • 632
  • 10
  • 24
-1

You need a third entity to tie the two together. In Database terms, it is called a junction table.

Captain Kenpachi
  • 6,960
  • 7
  • 47
  • 68
  • 1
    I am not sure who upvoted this, but this doesn't answer anything as the junction table is already there, see the `UserRoles` entity in the question's code. – Camilo Terevinto Sep 11 '18 at 13:22