Я добавил живой пример, чтобы сделать то, что вы хотите , с которым вы можете играть на Gistlyn .
В OrmLite каждый класс Data Model отображается 1: 1 с базовой таблицей, и естьнет волшебной поддержки запросов M: M, вы должны использовать их в качестве разных таблиц, так как они хранятся в RDBMS.
Кроме того, каждой таблице нужен уникальный первичный идентификатор в OrmLite, который отсутствует в BookAuthor
, который я добавил, я также добавил [UniqueConstraint]
, чтобы исключить дублирующиеся отношения, с этими изменениями получающиеся классывыглядит так:
public class Book
{
[AutoIncrement]
public int Id {get; set;}
public string Title {get; set;}
[Reference]
public List<BookAuthor> BookAuthors {get; set;}
}
[UniqueConstraint(nameof(BookId), nameof(AuthorId))]
public class BookAuthor
{
[AutoIncrement] public int Id {get; set;}
[ForeignKey(typeof(Book))]
public int BookId {get; set;}
[ForeignKey(typeof(Author))]
public int AuthorId {get; set;}
}
public class Author
{
[AutoIncrement]
public int Id {get; set;}
public string Name {get; set;}
}
public class BookDto
{
public int Id { get; set; }
public string Title { get; set; }
public List<Author> Authors { get; set; }
}
Затем создайте таблицы и добавьте некоторые примеры данных:
db.CreateTable<Book>();
db.CreateTable<Author>();
db.CreateTable<BookAuthor>();
var book1Id = db.Insert(new Book { Title = "Book 1" }, selectIdentity:true);
var book2Id = db.Insert(new Book { Title = "Book 2" }, selectIdentity:true);
var book3Id = db.Insert(new Book { Title = "Book 3" }, selectIdentity:true);
var authorAId = db.Insert(new Author { Name = "Author A" }, selectIdentity:true);
var authorBId = db.Insert(new Author { Name = "Author B" }, selectIdentity:true);
db.Insert(new BookAuthor { BookId = 1, AuthorId = 1 });
db.Insert(new BookAuthor { BookId = 1, AuthorId = 2 });
db.Insert(new BookAuthor { BookId = 2, AuthorId = 2 });
db.Insert(new BookAuthor { BookId = 3, AuthorId = 2 });
Затем, чтобы выбрать несколько таблиц в одном запросе в OrmLite, вы можете использовать SelectMulti , например:
var q = db.From<Book>()
.Join<BookAuthor>()
.Join<BookAuthor,Author>()
.Select<Book,Author>((b,a) => new { b, a });
var results = db.SelectMulti<Book,Author>(q);
Поскольку имена свойств соответствуют ссылочным соглашениям , их объединения не нужно указывать явно, поскольку они могут быть неявно выведены.
Это вернет List<Tuple<Book,Author>>
, который вы затем можете использовать в словаре, чтобы сшить всех авторов с их книгами:
var booksMap = new Dictionary<int,BookDto>();
results.Each(t => {
if (!booksMap.TryGetValue(t.Item1.Id, out var dto))
booksMap[t.Item1.Id] = dto = t.Item1.ConvertTo<BookDto>();
if (dto.Authors == null)
dto.Authors = new List<Author>();
dto.Authors.Add(t.Item2);
});
Мы можем получить список книг из словаря Значения:
var dtos = booksMap.Values;
dtos.PrintDump();
Там, где книги заполнены авторами и распечатываются:
[
{
Id: 1,
Title: Book 1,
Authors:
[
{
Id: 1,
Name: Author A
},
{
Id: 2,
Name: Author B
}
]
},
{
Id: 2,
Title: Book 2,
Authors:
[
{
Id: 2,
Name: Author B
}
]
},
{
Id: 3,
Title: Book 3,
Authors:
[
{
Id: 2,
Name: Author B
}
]
}
]
AutoQuery
AutoQuery может реализовывать только неявные запросы, которые он может автоматизировать, если вынужно сделатьлюбые пользовательские запросы или проекции, которые вам нужно будет предоставить настраиваемой реализации AutoQuery , поскольку объединения могут быть неявно определены, возможно, вы можете позволить AutoQuery создавать объединенный запрос, поэтому вам нужно только предоставить настраиваемую проекцию Select()
и отображение себя, например:
[Route("/books/query")]
public class QueryBooks : QueryDb<Book,BookDto>,
IJoin<Book,BookAuthor>,
IJoin<BookAuthor,Author> {}
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
//Override with custom implementation
public object Any(QueryBooks query)
{
var q = AutoQuery.CreateQuery(query, base.Request)
.Select<Book,Author>((b,a) => new { b, a });
var results = db.SelectMulti<Book,Author>(q);
var booksMap = new Dictionary<int,BookDto>();
results.Each(t => {
if (!booksMap.TryGetValue(t.Item1.Id, out var dto))
booksMap[t.Item1.Id] = dto = t.Item1.ConvertTo<BookDto>();
if (dto.Authors == null)
dto.Authors = new List<Author>();
dto.Authors.Add(t.Item2);
});
return new QueryResponse<BookDto> { Results = booksMap.Values.ToList() };
}
}