我正在进行一个简单的映射EntityFramework<> DTO,它的延迟执行完全正常,我有以下代码:
public abstract class Assembler<TDto, TEntity> : IAssembler<TDto, TEntity>
where TEntity : EntityBase , new ()
where TDto : DtoBase, new ()
{
public abstract TDto Assemble(TEntity domainEntity);
public abstract TEntity Assemble(TEntity entity, TDto dto);
public virtual IQueryable<TDto> Assemble(IQueryable<TEntity> domainEntityList)
{
List<TDto> dtos = Activator.CreateInstance<List<TDto>>();
foreach (TEntity domainEntity in domainEntityList)
{
dtos.Add(Assemble(domainEntity));
}
return dtos.AsQueryable();
}
public virtual IQueryable<TEntity> Assemble(IQueryable<TDto> dtoList)
{
List<TEntity> domainEntities = Activator.CreateInstance<List<TEntity>>();
foreach (TDto dto in dtoList)
{
domainEntities.Add(Assemble(null, dto));
}
return domainEntities.AsQueryable();
}
}
示例汇编程序:
public partial class BlogEntryAssembler : Assembler<BlogEntryDto, BlogEntry>, IBlogEntryAssembler
{
public override BlogEntry Assemble(BlogEntry entity, BlogEntryDto dto)
{
if (entity == null)
{
entity = new BlogEntry();
}
/*
entity.Id = dto.Id;
entity.Created = dto.Created;
entity.Modified = dto.Modified;
entity.Header = dto.Header;
*/
base.MapPrimitiveProperties(entity, dto);
this.OnEntityAssembled(entity);
return entity;
}
public override BlogEntryDto Assemble(BlogEntry entity)
{
BlogEntryDto dto = new BlogEntryDto();
//dto.Id = entity.Id;
//dto.Modified = entity.Modified;
//dto.Created = entity.Created;
//dto.Header = entity.Header;
base.MapPrimitiveProperties(dto, entity);
dto.CategoryName = entity.Category.Name;
dto.AuthorUsername = entity.User.Username;
dto.AuthorFirstName = entity.User.FirstName;
dto.AuthorLastName = entity.User.LastName;
dto.TagNames = entity.Tags.Select(t => t.Name)
.ToArray();
dto.TagIds = entity.Tags.Select(t => t.Id)
.ToArray();
dto.VotedUpUsernames = entity.BlogEntryVotes.Where(v => v.Vote > 0)
.Select(t => t.User.Username)
.ToArray();
dto.VotedDownUsernames = entity.BlogEntryVotes.Where(v => v.Vote < 0)
.Select(t => t.User.Username)
.ToArray();
// Unmapped
dto.FileCount = entity.BlogEntryFiles.Count();
dto.CommentCount = entity.BlogEntryComments.Count();
dto.VisitCount = entity.BlogEntryVisits.Count();
dto.VoteCount = entity.BlogEntryVotes.Count();
dto.VoteUpCount = entity.BlogEntryVotes.Count(v => v.Vote.Equals(1));
dto.VoteDownCount = entity.BlogEntryVotes.Count(v => v.Vote.Equals(-1));
dto.VotePuntuation = entity.BlogEntryVotes.Sum(v => v.Vote);
dto.Published = entity.Visible && entity.PublishDate <= DateTime.Now;
this.OnDTOAssembled(dto);
return dto;
}
}
我的服务类:
public virtual PagedResult<BlogEntryDto> GetAll(bool includeInvisibleEntries, string tag, string search, string category, Paging paging)
{
var entries = this.Repository.GetQuery()
.Include(b => b.Tags)
.Include(b => b.User)
.Include(b => b.Category)
.Include(b => b.BlogEntryFiles)
.Include(b => b.BlogEntryComments)
.Include(b => b.BlogEntryPingbacks)
.Include(b => b.BlogEntryVisits)
.Include(b => b.BlogEntryVotes)
.Include(b => b.BlogEntryImages)
.AsNoTracking();
if (!includeInvisibleEntries)
{
entries = entries.Where(e => e.Visible);
}
if (!string.IsNullOrEmpty(category))
{
entries = entries.Where(e => e.Category.Name.Equals(category, StringComparison.OrdinalIgnoreCase));
}
if (!string.IsNullOrEmpty(tag))
{
entries = entries.Where(e => e.Tags.Count(t => t.Name.Equals(tag, StringComparison.OrdinalIgnoreCase)) > 0);
}
if (!string.IsNullOrEmpty(search))
{
foreach (var item in search.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
entries = entries.Where(e => e.Header.Contains(item));
}
}
return this.Assembler.Assemble(entries).GetPagedResult(paging);
}
当我调用GetAll方法时,它返回并将表中的所有实体转换为Dto's,然后它才会对结果集合进行分页,当然这不是我所期待的..我想在我的Assemble中执行代码一旦分页完成,任何想法?
PS:我知道我可以使用Automapper,只是想学习内部。
答案 0 :(得分:2)
在汇编程序中,您将投影的DTO添加到List<TDto>
。这在两个方面是有害的。首先,它是强制执行,因为列表已填充然后返回。其次,在那一刻,你从LINQ切换到实体到LINQ再到对象,没有办法回来。您可以通过IQueryable
再次将列表转换为AsQueryable
,但这不会重新注入EF查询提供程序。事实上,转换是没用的。
这就是为什么AutoMapper的ProjectTo<T>
声明太酷了。它将To
之后的表达式一直传回原始IQueryable
,从而传递给它的查询提供程序。如果这些表达式包含分页语句(Skip/Take
),则这些语句将被转换为SQL。所以我认为你很快就会得出结论,毕竟你最好使用AutoMapper。
答案 1 :(得分:1)
public virtual IQueryable<TDto> Assemble(IQueryable<TEntity> domainEntityList)
{
List<TDto> dtos = Activator.CreateInstance<List<TDto>>();
foreach (TEntity domainEntity in domainEntityList)
{
dtos.Add(Assemble(domainEntity));
}
return dtos.AsQueryable();
}
上面代码中的foreach循环是您在数据库服务器上执行查询的时间点。
从这一行可以看出:
返回this.Assembler.Assemble(entries).GetPagedResult(paging);
在GetPagedResult(paging)之前调用此方法..这就是在完整结果集上发生分页的原因。
您应该了解枚举查询(foreach)需要运行查询。你的foreach循环处理那个查询返回的每一条记录..现在为时间太晚,Paging方法无法阻止它!