Запрос LINQ для получения данных из таблицы, расположенной на расстоянии трех таблиц

#c# #asp.net #database #linq #asp.net-core

#c# #asp.net #База данных #linq #asp.net-core

Вопрос:

У меня есть три таблицы.

  1. Организационная единица
  2. пользователь
  3. Задачи

Я хочу вернуть данные из таблицы задач, где авторизованный пользователь находится в определенном отделе, и пользователь тоже находится в этом отделе. Например, Салли работает в отделе кадров. Она хочет просмотреть задачи Джима. Джим также работает в отделе кадров с Салли, поэтому ей разрешено просматривать его задачи. Однако она не должна иметь возможности просматривать задачи Джона, поскольку он находится в отделе продаж.

 organisationalUnit
--------------------
ID     |     name
--------------------
1      |     HR
2      |     Sales




      Users
----------------------------------------
ID     |     name     |  OUID(FK)
----------------------------------------
4      |     Jim      |  1
5      |     Sally    |  1
6      |     John     |  2



      Tasks
----------------------------------------------
ID     |     TaskInfo           |  userID(FK)
-----------------------------------------------
1      |     Task for Jim       |     4
2      |     Task for john      |     5
3      |     Task for Sally     |     6
  

текущий код LINQ

 public async Task<IEnumerable<TaskSchedule>> GetTasks(string RoleName)
{         
     // return back ou ID
     var OUObjReturned = _context.OrganisationalUnits.Where(o => o.Name == RoleName).ToList();
     var OUID = OUObjReturned[0].Id;

     // get users based on the OUID       
     var userObjects = _context.Users.Where(u => u.OUId == OUID).ToList();

     // returns back with an array of users that have the Organisational unit ID   
     var userIDFromObject = userObjects[0].Id;

     //need further code to query the task table to return back tasks based on userID


}
  

Теперь я застрял на том, что делать после того, как я верну список пользователей с их идентификаторами. Есть ли лучший способ закодировать запрос LINQ, чем тот, который я сделал выше?

Запрос LING должен иметь возможность возвращать список задач на основе идентификатора OrganizationalUnit, который сначала отправляется в запрос. В приведенном выше случае отправка идентификатора организационной единицы, равного 1, должна вернуть строки задачи 1 и 2, поскольку Джим и Салли находятся в OUID 1.

Ответ №1:

Попробуйте приведенный ниже linq:

 var roleName = "HR";
var tasks = (from t in _context.Tasks
            join u in _context.Users on t.UserId equals u.Id
            join o in _context.OrganisationalUnits on u.OUID equals o.Id
            where o.Name == RoleName
            select t).ToList();
  

Ниже приведен Тест:

 public class OrganisationalUnit
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    [ForeignKey("OrganisationalUnit")]
    public int OUID { get; set; }
}

public class Task
{
    public int Id { get; set; }
    public string TaskInfo { get; set; }
    [ForeignKey("User")]
    public int UserId { get; set; }
}
  

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

Результат:

введите описание изображения здесь

Ответ №2:

 public async Task<IEnumerable<TaskSchedule>> GetTasks(string RoleName)
{
   // Here you found the OU
   var OUObjReturned = await _context.OrganisationalUnits
    .Where(o => o.Name == RoleName)
    .FirstOrDefault();

   // Now get list of users id
   var userObjects = await _context.Users
    .Where(u => u.OUId == OUObjReturned.ID)
    .Select(u => u.ID)
    .ToListAsync();

   // Return Tasks
   return await _context.Tasks
    .Where(t => userObjects.Contains(t.UserID)
    .ToListAsync();

}
  

Но есть другой способ: (при условии, что FK хорошо сконфигурирован) и модели включают свойства навигации, например: Пользователь должен включить ссылку на OrganizationalUnit:

 public class User
   {
      public int ID {get; set;}
      public string Name {get; set;}
      public OrganizationalUnit OU {get; set;}
      public int OUID {get; set;}
   }
  

Теперь вы можете запрашивать напрямую, используя свойства навигации, см. Отношения EF Net Core

 public async Task<IEnumerable<TaskSchedule>> GetTasks(string RoleName)
{
   // Return Tasks
   return await _context.Tasks
    .Include(t => t.User)
    .Where(t => User.OU.Name == RoleName)
    .ToListAsync();
}