servicestack 如何使用autoquery返回多对多关系的嵌套对象
假设我有3门课:
servicestack 如何使用autoquery返回多对多关系的嵌套对象,
servicestack,
servicestack,假设我有3门课: public class Book { [Autoincrement] public int Id {get; set;} public string Title {get; set;} [Reference] public list<BookAuthor> BookAuthors {get; set;} } public class BookAuthor { [ForeignKey(typeof(Book))]
public class Book
{
[Autoincrement]
public int Id {get; set;}
public string Title {get; set;}
[Reference]
public list<BookAuthor> BookAuthors {get; set;}
}
public class BookAuthor
{
[ForeignKey(typeof(Book))]
public int BookId {get; set;}
[Reference]
public Book Book {get; set;}
[ForeignKey(typeof(Author))]
public int AuthorId {get; set;}
[Reference]
public Author Author {get; set;}
}
public class Author
{
[Autoincrement]
public int Id {get; set;}
public string Name {get; set;}
}
公共课堂教材
{
[自动增量]
公共int Id{get;set;}
公共字符串标题{get;set;}
[参考]
公共列表图书作者{get;set;}
}
公共类图书作者
{
[外键(书的类型))]
public int BookId{get;set;}
[参考]
公共图书{get;set;}
[ForeignKey(类型(作者))]
公共int AuthorId{get;set;}
[参考]
公共作者{get;set;}
}
公共类作者
{
[自动增量]
公共int Id{get;set;}
公共字符串名称{get;set;}
}
书籍和作者之间存在着多对多的关系
这是我目前正在构建的应用程序的常见问题,我需要向前端提供如下DTO:
public class BookDto
{
public int Id {get; set;}
public string Title {get; set;}
public list<Author> Authors {get; set;}
}
public class BookDto
{
公共int Id{get;set;}
公共字符串标题{get;set;}
公共列表作者{get;set;}
}
前端需要嵌入作者。我需要一种在单个查询中将作者嵌套在DTO中的方法
这可能吗?我添加了一个实例来实现您的愿望 在OrmLite中,每个数据模型类都与底层表1:1映射,并且没有对M:M查询的神奇支持,您必须将它们作为不同的表使用,并将它们存储在RDBMS中 此外,每个表在OrmLite中都需要一个唯一的主Id,这在我添加的
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; }
}
书中有作者并打印出来:
[
{
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构造联接查询,因此您只需自己提供自定义的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() };
}
}
[路线(“/books/query”)]
公共类QueryBooks:QueryDb,
伊金,
IJoin{}
公共类MyQueryServices:服务
{
公共IAutoQueryDb自动查询{get;set;}
//用自定义实现重写
公共对象任意(QueryBooks查询)
{
var q=AutoQuery.CreateQuery(查询,base.Request)
.选择((b,a)=>new{b,a});
var结果=分贝。选择多(q);
var booksMap=newdictionary();
结果:每个(t=>{
if(!booksMap.TryGetValue(t.Item1.Id,out var dto))
booksMap[t.Item1.Id]=dto=t.Item1.ConvertTo();
if(dto.Authors==null)
dto.Authors=新列表();
dto.Authors.Add(t.Item2);
});
返回新的QueryResponse{Results=booksMap.Values.ToList()};
}
}
谢谢您的回复。是否可以使用AutoQuery执行此操作?前端希望使用隐式查询。可以将“选择多个”与“自动查询”结合使用吗?我希望所有的过滤器都能正常工作,但在QueryResponse@Guerrilla没有自动查询只能创建可以隐式自动执行的查询,您可以尝试添加自定义实现,我已经用一个示例更新了答案。感谢Mythz,我非常感谢AutoQueryHi Mythz的更新,如果书籍
没有作者
,则此操作无效。以这种方式使用SelectMulti时,它不会返回每本书籍
。它只返回包含作者的书籍
。我需要归还每一本作者为空的书。可能吗?我需要返回图书集合,如果它们有作者嵌套,如果没有,则不会嵌套任何内容。@Guerrilla这是内部联接的行为,否则您需要使用ILeftJoin
我不知道所讨论的语言是如何工作的,但通过链接对象数组在图书对象上定义关系似乎是多余的。为什么这本书不只是拥有一系列作者,而作者拥有一系列书籍?如果在更深的层次上有额外的繁重工作,比如关系数据库,它应该能够根据变量名本身作为关系名和我想要的书作为左侧连接键来进行查找。嗯,我不确定我是否理解你。假设我想得到一位作家写的所有书。如果authors是book上的一个数组,我该怎么做呢?Author对象不会存在于Books>authors数组中,它只是指向与该书相关的作者的指针。相反,作者将拥有一个Books数组来获取该方向上的所有相关方向。但我怀疑我只是误解了这种语言的工作原理,或者只是因为我对命名惯例有顾虑。如果它是列出作者
,那么对我来说可能更有意义,因此很明显,您正在检索作者列表,而不是检索关系本身。但即便如此,类型似乎也应该反映列表本身的内容。再一次,可能是过度思考,以及将我对某事物的总体看法强加给我实际上不知道的语言模式。或者是更多的过度思考:列表类型应该是BookAuthors,但它应该被定义为BookAuthors作者对象列表,通知Book对象如何获取对象(通过BookAuthors getter方法)以及如何与结果交互(作为作者列表)。然后,作者将使用相同的BookAuthors列表类型,但它将被定义为包含书籍对象的该类型的列表。
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
}
]
}
]
[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() };
}
}