. net GraphQL热巧克力投影仅适用于请求的实体列表,而不适用于请求的单个实体



所以如果我理解正确的话,投影是用来摆脱Over/Under抓取问题的,你会用正常的rest - api。

我已经为我的Author-ObjectType实现了一个gettall功能,在那里它工作得很好。我的问题是我不会让它为我的GetById功能工作。

我的意思是不工作,总是完整的SQL语句被触发到数据库中,而不仅仅是所请求的字段被选中。

也许我理解错了,投影只适用于实体列表?或者在本例中是IQueryables。

如果这只适用于列表/IQueryables,那么对于过滤过的实体(比如我想通过ID或名称等来获取作者),有什么方法可以实现它呢?

CallHierarchy: AuthorQuery ->AuthorService→库

AuthorQuery:

[ExtendObjectType(typeof(Query))]
public class AuthorQuery {
[UseProjection]
public async Task<IQueryable<Author>> Authors([Service] IAuthorService authorService) {
return await authorService.GetAsync();
}
[UseProjection]
public async Task<Author> AuthorById([Service] IAuthorService authorService, int id) {
var result = await authorService.GetAsync(author => author.Id == id);
return result.Single();
}
}

AuthorService(此时只是基础服务,因为AuthorService调用父方法):

public class BaseService<TEntity> : IBaseService<TEntity> where TEntity : BaseEntity {
protected readonly IRepository<TEntity> repository;
public BaseService(IRepository<TEntity> repository) {
this.repository = repository;
}
public virtual async Task<IQueryable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes) {
return await repository.GetAsync(filter, includes);
}
public virtual async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes) {
return await repository.GetFirstAsync(filter, includes);
}
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity {
protected readonly LibraryContext context;
public Repository(IDbContextFactory<LibraryContext> contextFactory) {
this.context = contextFactory.CreateDbContext();
}
public async Task<IQueryable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes) {
IQueryable<TEntity> query = context.Set<TEntity>();
foreach (var include in includes) {
query = query.Include(include);
}
if (filter != null) {
query = query.Where(filter);
}
return query.AsQueryable();
}
public async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes) {
IQueryable<TEntity> query = context.Set<TEntity>();
foreach (var include in includes) {
query = query.Include(include);
}
if (filter != null) {
query = query.Where(filter);
}
return await query.AsQueryable().FirstOrDefaultAsync();
}
}

AuthorType定义:

public class AuthorType: ObjectType<Author> { }

Program.cs——比;只定义服务和GraphQL特定的东西

builder.Services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
builder.Services.AddTransient(typeof(IBookRepository), typeof(BookRepository));
builder.Services.AddTransient(typeof(IAuthorRepository), typeof(AuthorRepository));
builder.Services.AddTransient(typeof(IBaseService<>), typeof(BaseService<>));
builder.Services.AddTransient<IBookService, BookService>();
builder.Services.AddTransient<IAuthorService, AuthorService>();
builder.Services
.AddGraphQLServer()
.AddProjections()
.AddQueryType<Query>()
.AddTypeExtension<BookQuery>()
.AddTypeExtension<AuthorQuery>()
.AddMutationType<Mutation>()
.AddTypeExtension<BookMutation>()
.AddTypeExtension<AuthorMutation>()
.AddType<BookType>()
.AddType<AuthorType>()
.AddType<BookCreate>()
.AddType<BookUpdate>()
.AddType<AuthorCreate>()
.AddType<AuthorUpdate>();

这是为以下请求字段生成的sql语句:

{
id
firstName        
books {
id
title
}
}

Update:(生成的sql查询)

ByAuthorId:

LastName在查询

SELECT [a].[Id], [a].[FirstName], [a].[LastName], [t].[AuthorsId], [t].[BooksId], [t].[Id], [t].[Title]
FROM [Authors] AS [a]
LEFT JOIN (
SELECT [a0].[AuthorsId], [a0].[BooksId], [b].[Id], [b].[Title]
FROM [AuthorBook] AS [a0]
INNER JOIN [Books] AS [b] ON [a0].[BooksId] = [b].[Id]
) AS [t] ON [a].[Id] = [t].[AuthorsId]
WHERE [a].[Id] = @__id_0
ORDER BY [a].[Id], [t].[AuthorsId], [t].[BooksId]

LastName已被忽略GetAll:

SELECT [a].[Id], [a].[FirstName], [t].[Id], [t].[Title], [t].[AuthorsId], [t].[BooksId]
FROM [Authors] AS [a]
LEFT JOIN (
SELECT [b].[Id], [b].[Title], [a0].[AuthorsId], [a0].[BooksId]
FROM [AuthorBook] AS [a0]
INNER JOIN [Books] AS [b] ON [a0].[BooksId] = [b].[Id]
) AS [t] ON [a].[Id] = [t].[AuthorsId]
ORDER BY [a].[Id], [t].[AuthorsId], [t].[BooksId]

从BaseService, AuthorService和AuthorRepository更新(2)代码

public class BaseService<TEntity> : IBaseService<TEntity> where TEntity : BaseEntity {
protected readonly IRepository<TEntity> repository;
public BaseService(IRepository<TEntity> repository) {
this.repository = repository;
}
public virtual async Task<IQueryable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes) {
return await repository.GetAsync(filter, includes);
}
public virtual async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes) {
return await repository.GetFirstAsync(filter, includes);
}
public virtual Task<TEntity> AddAsync(TEntity entity) {
return repository.AddAsync(entity);
}
public virtual async Task<TEntity> UpdateAsync(TEntity entity) {
return await repository.UpdateAsync(entity);
}
public virtual async Task<bool> ExistsAsync(int id) {
return await repository.ExistsAsync(id);
}
public virtual async Task RemoveAsync(TEntity entity) {
await repository.RemoveAsync(entity);
}
}
public class AuthorService : BaseService<Author>, IAuthorService {
public AuthorService(IAuthorRepository repository) : base(repository) {
}
}

AuthorRepository:

public class AuthorRepository : Repository<Author>, IAuthorRepository {
public AuthorRepository(IDbContextFactory<LibraryContext> contextFactory) : base(contextFactory) { }
public override async Task<Author> AddAsync(Author author) {
author.Books = await context.Books.Where(book => author.Books.Select(x => x.Id).ToList().Contains(book.Id)).ToListAsync();
return await base.AddAsync(author);
}
public override async Task<Author> UpdateAsync(Author author) {
var authorToUpdate = await GetFirstAsync(a => a.Id == author.Id, a => a.Books);
if (authorToUpdate == null) {
throw new ArgumentNullException(nameof(authorToUpdate));
}
authorToUpdate.FirstName = author.FirstName;
authorToUpdate.LastName = author.LastName;
if (author.Books.Count != authorToUpdate.Books.Count || !authorToUpdate.Books.All(author.Books.Contains)) {
authorToUpdate.Books.UpdateManyToMany(author.Books, b => b.Id);
authorToUpdate.Books = await context.Books.Where(book => author.Books.Select(a => a.Id).ToList().Contains(book.Id)).ToListAsync();
}
return await base.UpdateAsync(authorToUpdate);
}
}

请注意,我像下面这样更新了AuthorQuery的AuthorById函数,就像建议的那样

[UseProjection]
[UseSingleOrDefault]
public async Task<IQueryable<Author>> AuthorById([Service] IAuthorService authorService, int id) {
return await authorService.GetAsync(author => author.Id == id, author => author.Books);
}

你试过了吗?

[ExtendObjectType(typeof(Query))]
public class AuthorQuery {
[UseProjection]
public async Task<IQueryable<Author>> Authors([Service] IAuthorService authorService) {
return await authorService.GetAsync();
}
[UseSingleOrDefault]
[UseProjection]
public async Task<IQueryable<Author>> AuthorById([Service] IAuthorService authorService, int id) {
return await authorService.GetAsync(author => author.Id == id);
}
}

相关内容

最新更新