Member 14830098 Ответов: 2

Вычислите среднее значение с помощью двух таблиц


В проекте у меня есть две таблицы

- Ресторан (RestaurantId, Название, Адрес)
- RestaurantReview (ReviewId, RestaurantId, Mark)
У одного ресторана может быть несколько мнений. Я бы хотел, чтобы мое приложение отображало ресторан и средние его рейтинги. Я создаю код:

var resReviews = (
  from x in _context.Restaurant
  join y in _context.Reviews on x.IdRestauracji equals y.RestaurantId into z
  from a in z
  group a by a.RestaurantId into g
  select new
  {

     RatingAverage = g.Average(x => Convert.ToInt32(x.Mark))
  }
).ToList();


В списке сохраняются рассчитанные средние отметки. Я также хотел бы, чтобы информация о ресторане была сохранена в списке. Я пытаюсь создать что-то вроде этого, но это не работает:

var resReviews = (
  from x in _context.Restaurant
  join y in _context.Reviews on x.IdRestauracji equals y.RestaurantId into z
  from a in z
  group a by a.RestaurantId into g
  select new
  {
     Restaurant = g.FirstOrDefault();
     RatingAverage = g.Average(x => Convert.ToInt32(x.Mark))
  }
).ToList();


Что я уже пробовал:

var lj = (from x in _context.Restaurant
                      join y in _context.Reviews on x.RestaurantId equals y.RestaurantId into z
                      select new
                      {
                          Name= x.Name,
                          Total = z.Average(x => Convert.ToInt32(x.Mark))
                      }).ToList();

возвращать ошибку:
System.InvalidOperationException: „Processing of the LINQ expression 'GroupJoin<Restaurant, Reviews, int, <>f__AnonymousType4<string, double>>(
    outer: DbSet<Restaurant>, 
    inner: DbSet<Reviews>, 
    outerKeySelector: (x) => x.RestaurantId, 
    innerKeySelector: (y) => y.RestaurantId, 
    resultSelector: (x, z) => new { 
        Name = x.Name, 
        Total = Average<Review>(
            source: z, 
            selector: (x) => ToInt32(x.Marks))
     })' by 'NavigationExpandingExpressionVisitor' failed. 

2 Ответов

Рейтинг:
1

Richard Deeming

Предполагая, что у вас есть подходящие навигационные свойства, попробуйте что-то вроде этого:

var resReviews = _context.Restaurant.Select(x => new
{
    x.Name,
    RatingAverage = x.Reviews.Average(r => r.Mark)
}).ToList();
NB: Вы же не хотите конвертировать Mark к целому числу перед вычислением среднего, так как это приведет к перетаскиванию среднего вниз. Используя целые числа, среднее значение 1 и 2 будет 1, тогда как истинное среднее значение должно быть 1.5.


Maciej Los

5ed!

Рейтинг:
0

George Swan

Могу я предложить вам сделать что-нибудь подобное? Группа Reviews Collection by RestaurantId в качестве ключа и используйте Mark свойство для коллекции, относящейся к этому ключу. Выведите результат для каждой группы в виде кортежа значений, состоящего из RestaurantId а среднее значение Mark коллекция. То Average метод принимает перечислимое число ints и возвращает double так что нет никакой необходимости преобразовывать Mark собственность в double.


var reviewResults = Reviews.GroupBy(r => r.RestaurantId, r => r.Mark, (key, marks) => (Id:key,AverageMark: marks.Average()));

Тогда присоединяйтесь к reviewResults к Restaurants коллекция RestaurantId чтобы включить любые дополнительные свойства из Restaurants коллекция, которая вам нужна.


var summaries= reviewResults.Join(Restaurants,  rev => rev.Id,  rest => rest.RestaurantId, (rev, rest) => (rest.Name,rev.AverageMark, rev.Id));

Вы можете перечислить summaries подобный этому


foreach(var(Name,Mark,Id)in summaries)
 {
   Console.WriteLine($"Restaurant {Name} Average Score {Mark}");
 }

В этом нет необходимости. summaries переменная. Я просто вставил это, чтобы упростить объяснение, вы можете соединить два оператора Linq вместе, используя точечную нотацию.