【问题标题】:Await results from DataContext.ExecuteQuery等待来自 DataContext.ExecuteQuery 的结果
【发布时间】:2021-06-16 18:09:24
【问题描述】:

我有一个由 MVC 控制器调用的方法,而 MVC 控制器又在 Web 应用程序中使用 Ajax 调用。它曾经看起来像这样:

public static IEnumerable<DepartmentViewModel> GetDepartments()
{
    DataContext db = new DataContext(ConfigurationHelper.DepartmentsConnectionString);
    string sql = "SELECT DISTINCT RTRIM(DEP_CODE) AS [DepartmentCode], RTRIM(DEP_NAME) AS 
        [DepartmentName] " +
        "FROM [departmentinfo].[dbo].[Dep_School_Faculty] " +
        "WHERE [DEPARTMENT_IN_USE] = 'Y' AND [VALID] = 'Y' " +
        "ORDER BY [DepartmentName]";
     IEnumerable<DepartmentViewModel> departments = db.ExecuteQuery<DepartmentViewModel>(sql);
     return departments;
}

SQL 查询需要几秒钟的时间来执行,这就是为什么 Ajax 在加载网页的其余部分后调用它的原因,因此用户可以在加载部门列表的同时继续处理其他内容。这很好用。

不过,现在我需要稍微修改查询,并在将后端数据的结果传递给控制器​​之前对其进行一些处理,因此我将方法更新为如下所示:

public static async Task<IEnumerable<AcademicAreaViewModel>> AllAcademicAreas()
{
    IEnumerable<DepartmentSchoolFacultyModel> deptSchoolFaculty = await GetAllAcademicAreas();
    using (DataContext db = new DataContext(ConfigurationHelper.DepartmentsConnectionString))
    {
        string sql = "SELECT DISTINCT RTRIM(DEP_CODE) AS [DepartmentCode], RTRIM(DEP_NAME) AS [DepartmentName], " +
            "RTRIM(SCHOOL_CODE) AS [SchoolCode], RTRIM(SCHOOL_NAME) AS [SchoolName], " +
            "RTRIM(FACULTY_CODE) AS [FacultyCode], RTRIM(FACULTY_NAME) AS [FacultyName] " +
            "FROM [departmentinfo].[dbo].[Dep_School_Faculty] " +
            "WHERE [DEPARTMENT_IN_USE] = 'Y' AND [VALID] = 'Y'";
        deptSchoolFaculty = db.ExecuteQuery<DepartmentSchoolFacultyModel>(sql);
    };

    IEnumerable<AcademicAreaViewModel> departments = deptSchoolFaculty
        .GroupBy(d => d.DepartmentCode)
        .Select(g => new AcademicAreaViewModel()
        {
            Name = g.First().DepartmentName,
            Code = "Department:" + g.First().DepartmentCode
        })
        .ToList();

    IEnumerable<AcademicAreaViewModel> schools = deptSchoolFaculty
        .GroupBy(d => d.SchoolCode)
        .Select(g => new AcademicAreaViewModel()
        {
            Name = g.First().SchoolName,
            Code = "School:" + g.First().SchoolCode
        })
        .ToList();

    IEnumerable<AcademicAreaViewModel> academicAreas = departments.Concat(schools);

    return academicAreas;
}

然后我遇到的问题是,以IEnumerable&lt;AcademicAreaViewModel&gt; departments = deptSchoolFaculty 开头的行抛出了一个空异常错误,因为deptSchoolFaculty 变量尚未填充数据。

所以,我想,这是一个典型的异步编程用例,恰好发生在我的克星身上(无论我读了多少关于这个主题或实施它,它永远不会在我的脑海中“点击”)。

我这样重构我的代码:

public static async Task<IEnumerable<AcademicAreaViewModel>> AllAcademicAreasAsync()
{
    IEnumerable<DepartmentSchoolFacultyModel> deptSchoolFaculty = await GetAllAcademicAreasAsync();

    IEnumerable<AcademicAreaViewModel> departments = deptSchoolFaculty
        .GroupBy(d => d.DepartmentCode)
        .Select(g => new AcademicAreaViewModel()
        {
            Name = g.First().DepartmentName,
            Code = "Department:" + g.First().DepartmentCode
        })
        .ToList();

    IEnumerable<AcademicAreaViewModel> schools = deptSchoolFaculty
        .GroupBy(d => d.SchoolCode)
        .Select(g => new AcademicAreaViewModel()
        {
            Name = g.First().SchoolName,
            Code = "School:" + g.First().SchoolCode
        })
        .ToList();

    IEnumerable<AcademicAreaViewModel> academicAreas = departments.Concat(schools);

    return academicAreas;
}

private static Task<IEnumerable<DepartmentSchoolFacultyModel>> GetAllAcademicAreasAsync()
{ 
    return Task.Run(() =>
    {
        IEnumerable<DepartmentSchoolFacultyModel> deptSchoolFaculty = new List<DepartmentSchoolFacultyModel>();
        using (DataContext db = new DataContext(ConfigurationHelper.DepartmentsConnectionString))
        {
            string sql = "SELECT DISTINCT RTRIM(DEP_CODE) AS [DepartmentCode], RTRIM(DEP_NAME) AS [DepartmentName] " +
                "FROM [departmentinfo].[dbo].[Dep_School_Faculty] " +
                "WHERE [DEPARTMENT_IN_USE] = 'Y' AND [VALID] = 'Y' " +
                "ORDER BY [DepartmentName]";
            
            return db.ExecuteQuery<DepartmentSchoolFacultyModel>(sql);
        }
    }); 
}

不幸的是,尽管我使用await 关键字,但我希望在继续之前等待 SQL 查询的结果,但同一行会引发相同的空异常错误。

首先,我不明白为什么,在我的代码的原始版本中,该方法似乎要等待SQL查询完成才能返回结果(因为结果总是返回到我的页面),但现在我正在尝试以相同的方法处理结果。

其次,虽然我怀疑我的问题的答案可能是使用asynchronous data methods 而不是DataContext.ExecuteQuery,但我想了解为什么我所写的内容不起作用。另外,我更喜欢 ExecuteQuery 的简洁性,因为它可以将 sql 查询的结果直接写入 C# 模型中。

【问题讨论】:

  • 问题:为什么是 SQL?这可以很容易地转换为 LINQ。
  • 公平的问题。这个数据库不是我的应用程序(我使用 EF)的主数据库,我只为这件事调用它,所以创建一个额外的 ADO 数据模型等等似乎有点过头了。
  • 你使用哪个 ORM?
  • 如果db.ExecuteQuery&lt;DepartmentSchoolFacultyModel&gt;(sql)返回IEnumerable,你必须在使用里面调用.ToList(),因为你dispose了DataContext,枚举无法完成。
  • 作为旁注,您使用Task.Runexpose an asynchronous wrapper for a synchronous method,并且您在Web 应用程序中这样做。现在等待斯蒂芬克利里来告诉你为什么this is a bad idea

标签: c# linq asynchronous async-await


【解决方案1】:

在完成枚举结果之前处理 DataContext 有问题。可以通过添加.ToList() 调用或扩展using 的范围来修复它。

deptSchoolFaculty = db.ExecuteQuery<DepartmentSchoolFacultyModel>(sql).ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-13
    • 2021-04-22
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多