简体   繁体   English

c# winforms 如何使用 LINQ 使用异步等待

[英]c# winforms How do I use async await using LINQ

I want to use async await function to group by age.我想使用 async await function 按年龄分组。 It's working fine without aync await, but I want use asyn await.没有 aync 等待它工作正常,但我想使用 async 等待。 If I exclude ToList() in firstline...from u in db.Patient.ToList()... then I get problem with CalculateAge function with error LINQ Entities does not recognize in the method CalculateAge(system.String).... That's why use it there.如果我在第一行中排除 ToList() ...从 db.Patient.ToList() 中的 u 中排除...然后我会遇到 CalculateAge function 错误 LINQ 实体在方法 CalculateAge(system.String) 中无法识别的问题... . 这就是为什么在那里使用它。 CalculateAge function is to calculate age and here is code function CalculateAge function 是计算年龄,这里是代码 function

private int CalculateAge(string birthday)
        {
            int age;
            if (string.IsNullOrWhiteSpace(birthday)) return 0;

            DateTime empBirthday = Convert.ToDateTime(birthday);
            DateTime today = DateTime.Today;
            age = today.Year - empBirthday.Year;
            if (empBirthday > today.AddYears(-age))
                age--;
            return age;
        }

This work fine without async await无需异步等待即可正常工作

private void btnByAge_Click(object sender, EventArgs e)
{
    var result = (from u in db.Patient.ToList() // 
                  join a in db.Analys on u.PatientId equals a.PatientId
                  where a.Status == Active
                  group u by CalculateAge(u.DOB.ToString()) into g
                  select new
                  {
                      Age = g.Key,
                      Amount = g.Count(),
                  }).Tolist();

    if (result != null)
    {
        dgvResult.DataSource = result;
    }
}

But not this with async await但这不是异步等待

private async void btnByAge_Click(object sender, EventArgs e)
{
    var result = (from u in db.Patient.ToListAsync()
                  join a in db.Analys on u.PatientId equals a.PatientId
                  where a.Status == Active
                  group u by CalculateAge(u.DOB.ToString()) into g
                  select new
                  {
                      Age = g.Key,
                      Amount = g.Count(),
                  });

    var data = await result.ToListAsync();
    if (data != null)
    {
        dgvResult.DataSource = data;
    }
}

Error I get is Error CS1936 Could not find an implementation of the query pattern for source type 'Task>'.我得到的错误是错误 CS1936 找不到源类型“任务>”的查询模式的实现。 'Join' not found... I have used even Using.System.Data.Linq, but the same problem. 'Join' not found...我什至使用了Using.System.Data.Linq,但同样的问题。 Please Help, thank you in advance!请帮忙,提前谢谢!

All you need to do to fix the error is to put an await before the db.Patient.ToListAsync() .修复错误所需要做的就是在db.Patient.ToListAsync()之前放置一个await However it would be better to not even do that ToList so that the join can be done in the DB.但是,最好不要这样做ToList以便可以在数据库中完成连接。 Also note you don't need the null check as the results will never be null (maybe empty or maybe an exception will be thrown, but they should never be null)另请注意,您不需要null检查,因为结果永远不会是null (可能为空或可能会引发异常,但它们永远不应为空)

var dobs = await (from u in db.Patient
                  join a in db.Analys on u.PatientId equals a.PatientId
                  where a.Status == Active
                  select u.DOB).ToListAsync();
var data = dobs
    .GroupBy(x => CalculateAge(x.toString())
    .Select(grp => new
    {
        Age = grp.Key,
        Amount = grp.Count(),
    })
    .ToList();

dgvResult.DataSource = data;    

That will do the join and filter on Status and select the DOBs in the DB and get the dobs asynchronously.这将对状态和 select 数据库中的 DOB 进行连接和过滤,并异步获取 DOB。 Then you can do the group by in memory since CalculateAge cannot be translated to SQL.然后您可以在 memory 中进行分组,因为CalculateAge无法转换为 SQL。 But an even better idea is to do the age calculation in the DB.但更好的主意是在数据库中进行年龄计算。

var now = DateTime.UtcNow(); // or .Now() if you don't store UTC in the DB
var result =  from u in db.Patient
              join a in db.Analys on u.PatientId equals a.PatientId
              where a.Status == Active
              let age = now.Year - u.DOB.Year -
                  ((u.DOB.Month < now.Month || 
                      (u.DOB.Month == now.Month && u.DOB.Day < now.Day))
                  ? 1 : 0)
              group u by age into g
              select new
              {
                  Age = g.Key,
                  Amount = g.Count(),
              };

dgvResult.DataSource = await result.ToListAsync();    

That determines the age by subtracting the DOB year from the current year and then subtracting 1 if the current day is before the Month and Day of the DOB.这通过从当前年份中减去 DOB 年份来确定年龄,如果当前日期在 DOB 的月份和日期之前,则减去 1。

Also if you plan to use CalculateAge then just pass the DateTime to it instead of formatting it to a string and then parsing that back to a DateTime .此外,如果您打算使用CalculateAge则只需将DateTime传递给它,而不是将其格式化为string ,然后将其解析回DateTime You can pass a DateTime?你可以传递一个DateTime? if it's possible that it might be null .如果它可能是null

private int CalculateAge(DateTime? birthday)
{
    int age;
    if (!birthday.HasValue) return 0;

    DateTime today = DateTime.Today;
    age = today.Year - birthday.Value.Year;
    if (birthday.Value > today.AddYears(-age))
        age--;
    return age;
}

Nothing special you can achieve this code in C#,look at below code.没什么特别的,你可以在 C# 中实现这个代码,看看下面的代码。

private async void button1_Click(object sender, EventArgs e)
    {
        var query = (from p in db.Patient
                     join An in db.Analys on p.PatientId equals An.PatientId
                     where An.Status == Active
                     select p.DOB)



       var Result=await query.GroupBy(x => CalculateAge(x.toString())
           .Select(g => new {
               Age = g.Key,
               Amount = g.Count(),
           }).ToListAsync();
 dgvResult.DataSource = Result
    }    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM