Как получить среднее значение, используя LEFT JOIN в LINQ и Lambda - PullRequest
0 голосов
/ 16 октября 2019

Я хочу отобразить среднюю оценку каждой книги с ее издателем, используя LINQ и Lambda.

Вот мой список книг

private List<Book> Books = new List<Book>(){
new Book {
Id: 1,
Name: Book A,
PublisherId: 1
}, new Book {
Id: 2,
Name: Book B,
PublisherId: 2
}, new Book {
Id: 3,
Name: Book C,
PublisherId: 1
}
};

Сначала я присоединяюсь к списку книг со списком издателей, используя этот запрос

 var bookPublisher = Books.SelectMany( book => Publishers.Where(publisher => book.PublisherId == publisher.Id),
            (book, publisher) => new { book, publisher });

Затем я пытаюсь использовать левое соединение со списком BookTransaction, чтобы получить подробный рейтинг для каждой книги. Вот мой список BookTransaction.

private List<Book_Transaction> BookTransactions = new List<Book_Transaction>() {
        new Book_Transaction {
            Id = 1,
            BookId = 1,
            CustomerId = 1,
            RatingStar = 4.5
        }, new Book_Transaction {
            Id = 2,
            BookId = 2,
            CustomerId = 1,
            RatingStar = 4
        }, new Book_Transaction {
            Id = 3,
            BookId = 1,
            CustomerId = 2,
            RatingStar = 5
        },new Book_Transaction {
            Id = 4,
            BookId = 2,
            CustomerId = 2,
            RatingStar = 3.5
        },new Book_Transaction {
            Id = 5,
            BookId = 1,
            CustomerId = 3,
            RatingStar = 4
        }};

, и вот мой запрос

var bookPublisherRating = bookPublisher.SelectMany(bp => BookTransactions.Where(bt => bp.book.Id == bt.BookId).DefaultIfEmpty(),
                (bp, bt) => new { BookPublish = bp, BookRating = bt.RatingStar });

в этом запросе, я получил сообщение о том, что "'Ссылка на объект не установлена ​​для экземпляра объекта. 'БТ был нулевым. "

Я пытался использовать другой подход, но в результате это просто та же ошибка.

var bookPublisherRating = bookPublisher.GroupJoin(BookTransactions,
            bp => bp.book.Id,
            bt => bt.BookId,
            (bp, bt) => new { BookPublish = bp, BookTrans = bt })
                .SelectMany(temp => temp.BookTrans.DefaultIfEmpty(),
                (temp, y) => new { BookPublish = temp.BookPublish, bookRating = y.RatingStar });

Может кто-нибудь сказать мне, где я был не прав? Когда я удалил функцию DefaultIfEmpty, она может отображать данные, но только в том случае, если в оба списка включено значение bookId, например:

| BookName  | PublisherName | Rating |
| Book A    | Publisher A   | 4.5    |
| Book A    | Publisher A   | 5      |
| Book A    | Publisher A   | 4      |
| Book B    | Publisher B   | 4      |
| Book B    | Publisher B   | 3.5    |

Я ожидаю, что результат запроса будет таким, как этот

| BookName  | PublisherName | Rating |
| Book A    | Publisher A   | 4.5    |
| Book B    | Publisher B   | 3.75   |
| Book C    | Publisher A   | 0      |

1 Ответ

0 голосов
/ 16 октября 2019

У Linq есть метод Average. Вы можете вызывать его для набора числовых значений или для набора объектов, передавая ему имя свойства для усреднения. Вы также можете позвонить GroupBy, чтобы создать пары ключей <->.

Таким образом, вы можете сгруппировать данные по BookId и найти среднюю оценку.

Предполагая следующее

public class Book_Transaction
{
    public int Id { get; set; }
    public int BookId { get; set; }
    public int CustomerId { get; set; }
    public double RatingStar { get; set; }
}

var bookTransactions = new List<Book_Transaction>() {
    new Book_Transaction {
        Id = 1,
        BookId = 1,
        CustomerId = 1,
        RatingStar = 4.5
    }, new Book_Transaction {
        Id = 2,
        BookId = 2,
        CustomerId = 1,
        RatingStar = 4
    }, new Book_Transaction {
        Id = 3,
        BookId = 1,
        CustomerId = 2,
        RatingStar = 5
    },new Book_Transaction {
        Id = 4,
        BookId = 2,
        CustomerId = 2,
        RatingStar = 3.5
    },new Book_Transaction {
        Id = 5,
        BookId = 1,
        CustomerId = 3,
        RatingStar = 4
    }};

Тогда

bookTransactions.GroupBy(
    bt => bt.BookId,
    (bookId, collection) => new {
        BookId = bookId,
        AverageRating = collection.Average(x => x.RatingStar)
    }).ToList()  

Создает следующий вывод в интерактивной консоли C #:

List<<>f__AnonymousType0#5<int, double>>(2) { 
    { BookId = 1, AverageRating = 4.5 }, 
    { BookId = 2, AverageRating = 3.75 }
}
...