c# winforms Как использовать asyn c, ожидайте с помощью LINQ - PullRequest
1 голос
/ 04 мая 2020

Я хочу использовать функцию asyn c await для группировки по возрасту. Работает нормально без ayn c await, но я хочу использовать asyn await. Если я исключаю ToList () в первой строке ... из u в db.Patient.ToList () ... тогда я получаю проблему с функцией CalculateAge с ошибкой LINQ Entities не распознает в методе CalculateAge (system.String) ... Вот почему использовать его там. Функция CalculateAge предназначена для вычисления возраста, а вот кодовая функция

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;
        }

Это прекрасно работает без асин c ожидание

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;
    }
}

Но не с асин c ожидание

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;
    }
}

Ошибка, которую я получаю: ошибка CS1936 Не удалось найти реализацию шаблона запроса для типа источника «Задача>». 'Join' не найден ... Я использовал даже Using.System.Data.Linq, но та же проблема. Пожалуйста, помогите, спасибо заранее!

Ответы [ 2 ]

2 голосов
/ 04 мая 2020

Все, что вам нужно сделать, чтобы исправить ошибку, это поставить await перед db.Patient.ToListAsync(). Однако было бы лучше даже не делать этого ToList, чтобы объединение могло быть выполнено в БД. Также обратите внимание, что вам не нужна проверка 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;    

Это будет выполните объединение и фильтрацию состояния, выберите DOB в базе данных и получите их асинхронно. Затем вы можете создать группу в памяти, поскольку CalculateAge не может быть переведено в SQL. Но еще лучшей идеей является вычисление возраста в БД.

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();    

Это определяет возраст путем вычитания года DOB из текущего года и затем вычитания 1, если текущий день предшествует месяцу, и Day of DOB.

Также, если вы планируете использовать CalculateAge, просто передайте ему DateTime вместо форматирования в string, а затем проанализируйте его обратно в DateTime. Вы можете передать DateTime?, если возможно, что это может быть 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;
}
0 голосов
/ 04 мая 2020

Ничего особенного вы не можете достичь этого кода в 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= query.GroupBy(x => CalculateAge(x.toString())
           .Select(g => new {
               Age = g.Key,
               Amount = g.Count(),
           }).ToListAsync();
 dgvResult.DataSource = Result
    }    
...