API控制器查询中间表的存储库模式问题

时间:2019-02-07 10:02:47

标签: c# asp.net .net-core

这里是存储库,在其中创建了一种方法,该方法中需要基于中间表的数据。

public Task<IEnumerable<DepartmentSchool>> GetAllDepartmentBySchoolIdAsync(int schoolId)
    {
        var school = _GpsContext.School.Where(e => e.ID == schoolId).FirstOrDefaultAsync();
        if (school == null)
            return NotFound();
        var departments = _GpsContext.DepartmentSchool
            .Where(e => e.SchoolsId == schoolId).Select(e => e.DepartmentID);
        return Ok(departments);

    }

然后从我的控制器类中调用该方法以基于该方法获取值。

[Route("api/[controller]")]
[ApiController]
public class DepartmentSchoolController : ControllerBase
{
    private readonly IDepartmentSchoolRepository _departmentSchoolRepository;
    public DepartmentSchoolController(DepartmentSchoolRepository departmentSchoolRepository)
    {
        _departmentSchoolRepository = departmentSchoolRepository;
    }

    /// <summary>
    /// Calling depatment on the basis of school id. 
    /// </summary>
    /// <param name="schoolId"></param>
    /// <returns></returns>
    [HttpGet("school/{schoolId}/departments")]
    public async Task<IEnumerable<DepartmentSchoolRepository>> GetDepartmentsFromSchool(int schoolId)
    {
        return await _departmentSchoolRepository.GetAllDepartmentBySchoolIdAsync();
    }

可以,请告诉我问题出在哪里。上面的代码不起作用,并且在NotFound()Ok()中显示出“当前上下文中不存在”的问题,我该怎么办?

这里是相关实体:

public class DepartmentSchool
{
    public int Id { get; set; }
    public int DepartmentID { get; set; }
    [ForeignKey("DepartmentID")]
    public virtual Department Department { get; set; }
    public int SchoolsId { get; set; }
    [ForeignKey("SchoolsId")]
    public virtual Schools Schools { get; set; }
}

public partial class Schools
{
    public int ID { get; set; }
    public DateTime UpdatedAt { get; set; }

}

public partial class Department
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int SchoolSystemsID { get; set; }
}

1 个答案:

答案 0 :(得分:0)

您的代码有很多问题,包括无法编译。

在您的控制器中:

  • 您不想从控制器返回存储库。由于您使用的是.net-core,为什么不将IActionResult类型用作per the docs

[HttpGet("school/{schoolId}/departments")]
public async Task<IActionResult> GetDepartmentsFromSchool(int schoolId)
{
    var departments = await _departmentSchoolRepository
        .GetAllDepartmentBySchoolIdAsync(schoolId);
    if (departments.Any())
    {
        return Ok(departments)
    }
    return NotFound();
}

在您的存储库中:

  • 您不等待任何一个EF呼叫。因此,这两个调用都将返回Task而不是您期望的EF实体类型。
  • 从方法的名称看来,您似乎要计划给定学校的所有系。为此,请使用您在EF模型中定义的导航属性。
  • 您需要实现第二个查询并更改返回类型(.ToListAsync()
  • 您还需要将方法标记为async
  • 请勿在存储库层中使用HTTP / Web Api之类的文件,例如Ok / NotFound,这应该保留给您的控制器层。
  • 出于您的理智,在LINQ中,使用表示它们表示的类型的lambda变量名称。例如我在下面的ds中使用了DepartmentSchool,在下面的s中使用了School

// ** Return type is the projected result
public async Task<IEnumerable<Department>> GetAllDepartmentBySchoolIdAsync(int schoolId) // ** async
{
    var school = await _GpsContext.School // ** await 
       .Where(s => s.ID == schoolId)
       .FirstOrDefaultAsync(); 
    if (school == null)
        return Enumerable.Empty<Department>(); // Avoid returning nulls
    var departments = await _GpsContext.DepartmentSchool // ** await
        .Where(ds => ds.SchoolsId == schoolId)
        .SelectMany(ds => ds.Department) // ** flatten and project the navigation property
        .ToListAsync(); // ** materialize
    return departments; // ** Don't use Http stuff like OK in Repo layer
}

还请注意,您的第一个查询实际上是多余的。如果您在数据库中强制实施了参照完整性,则不可能有DepartmentSchool个没有链接的School的联结行,因此您应该只寻找DepartmentSchool行。 / p>

在上面,我假设您已经启用了延迟加载。如果您不这样做,则需要将DepartmentSchool -> Department导航加载为per here