簡體   English   中英

使用IQueryable延遲執行

[英]using IQueryable deferred execution

我正在一個簡單的映射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,然后才分頁結果集合,這當然不是我所期望的。.我想在分頁已經完成,有什么主意嗎?

PS:我知道我可以使用Automapper,只是嘗試學習內部知識。

在匯編器中,將投影的DTO添加到List<TDto> 這從兩個方面來說都是有害的。 首先,它被強制執行,因為列表已填充,然后返回。 其次,在那一刻,您從LINQ切換到Entities,再從LINQ切換到對象,並且沒有退路。 您可以通過AsQueryable再次將列表轉換為IQueryable ,但這不會重新注入EF查詢提供程序。 實際上,轉換是沒有用的。

這就是AutoMapper的ProjectTo<T>語句如此酷的原因。 它將“ To之后的表達式一直傳遞回原始IQueryable並由此傳遞其查詢提供程序。 如果這些表達式包含分頁語句( Skip/Take ),則將它們轉換為SQL。 因此,我認為您很快就會得出一個結論,那就是最好還是使用AutoMapper。

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循環處理該查詢返回的每條記錄。.現在,分頁方法無法采取任何措施停止它了!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM