Dapper — создание объектов с запросами к базе данных с отношениями «один ко многим» и «многие ко многим»

#c# #.net #database #sqlite #dapper

#c# #.net #База данных #sqlite #dapper

Вопрос:

У меня есть база данных Sqlite, для которой частичная схема: введите описание изображения здесь

В коде классы, представляющие данные, выглядят следующим образом (упрощенно):

 public Book : Item
{
    public ICollection<Tag> Tags { get; set; }
    public ICollection<Author> Authors { get; set; }
    public Publisher publisher { get; set; }
    // other properties...
}

public class Publisher
{
    public ICollection<Book> Books { get; set; }
    // other properties...
}

public class Author
{
    public ICollection<Author> Authors { get; set; }
}

public class Tag
{
    public ICollection<Item> Items { get; set; }
}
 

Мне нужно вернуть an IEnumerable<Book> с Book объектами, содержащими все Author , Publisher и Tag данные для каждого Book . В настоящее время у меня есть следующий код, который решает проблему получения данных издателя:

 public IEnumerable<Book> GetAllBooks()
{
    using (var db = new SqliteConnection(connectionString)
    {
        var sql = "SELECT * FROM Books as B "  
                  "INNER JOIN Publishers AS P On B.publisherId = P.id;";
        var allBooks = db.Query<Book, Publisher, Book>(sql, (book, publisher) =>
        {
             book.publisher = publisher;
             return book;
        });
        return allBooks;
    }
}
 

Как получить оставшиеся данные для a Book (ie Author и Tag данные с отношениями «многие ко многим», как показано на схеме)?

Комментарии:

1. Вы имеете в виду получение коллекций Author (ов) и Tag (ов) для каждого Book внутри GetAllBooks() ?

2. @LuckyBrain это правильно.

Ответ №1:

Было бы не очень эффективно, если бы вы запрашивали книгу за книгой, поэтому я рекомендую сначала запросить все Author (ы), включая их Book.id , затем запросить все Tag (ы), включая их Book.id , а затем использовать LINQ для сопоставления Book.id по результатам этих запросов следующим образом:

 public IEnumerable<Book> GetAllBooks()
{
    using (var db = new SqliteConnection(connectionString))
    {
        var authorsSql = "SELECT A.*, B.id AS BookId FROM Books as B "  
                         "INNER JOIN Book_Author AS B2A On B.id = B2A.bookId "  
                         "INNER JOIN Author A On B2A.authorId = A.id;";
        var allAuthorsWithBookId = db.Query<dynamic>(authorsSql).AsList();

        var tagsSql = "SELECT T.*, B.id AS BookId FROM Books as B "  
                      "INNER JOIN Book_Tag AS B2T On B.id = B2T.bookId "  
                      "INNER JOIN Tags T On B2T.tagId = T.id;";
        var allTagsWithBookId = db.Query<dynamic>(tagsSql).AsList();

        var sql = "SELECT * FROM Books as B "  
                  "INNER JOIN Publishers AS P On B.publisherId = P.id;";
        var allBooks = db.Query<Book, Publisher, Book>(sql, (book, publisher) =>
        {
            book.publisher = publisher;
            book.Authors = allAuthorsWithBookId.Where(row => row.BookId == book.id).Select(row => new Author{ id = row.id, name = row.name }).AsList();
            book.Tags = allTagsWithBookId.Where(row => row.BookId == book.id).Select(row => new Tag{ id = row.id, name = row.name }).AsList();
            return book;
        });
        return allBooks;
    }
} 

Вам нужно будет исправить некоторые опечатки и структурный код (например, скобки в конце using ) и некоторые недостающие свойства в классах Author Tag и т. Д. Но после этого все должно быть в порядке.