如何在 DTO 中正确存储多个结果?

How to correctly store a number of results in a DTO?

我已将存储过程附加到数据库,它应该 return 只需简单搜索即可得到结果。查询被添加到我的实体并调用常规方法。我面临的问题是将此过程的结果作为列表存储到特定的 DTO。

有什么方法可以有效地将此存储过程的结果作为列表存储到 DTO 中吗?

以下是我目前所拥有的

Controller:

[Produces("application/json")]
    [RoutePrefix("api/jobs")]
    public class OutputController : ApiController
    {
        private TestCoastalToolsEntities _output;

        public OutputController()
        {
            _output = new TestCoastalToolsEntities();
            _output.Configuration.ProxyCreationEnabled = false;
        }        

        /**Search**/
        // POST: api/postsearch
        [System.Web.Http.HttpPost, System.Web.Http.Route("postsearch")]
        public async Task<IHttpActionResult> PostSearch(SearchInputDTO srequest)
        {
            OutputDTO<SearchInputDTO> output = new OutputDTO<SearchInputDTO>();
            SearchInputDTO SearchInput = null;
            var searchString = srequest.SearchValue.ToString();
            SearchInput.Results = _output.searchLog2(searchString);
            if (_oput != null)
            {
                output.Success = true;
                output.Results = _SearchInput.Results;
                var json = new JavaScriptSerializer().Serialize(output);
                return Ok(json);

            }
            return Ok(_ot);
        }

    }
}
-------------------------------------
Search DTO:

namespace toolPortal.API.Data.DTO
{
    public class SearchInputDTO
    {
        public List<object> Results { get; set; }
        public SearchInputDTO(output output) {
            this.ID = output.ID;
            this.Name = output.Name;
            this.Job = output.Job;
            this.Start = output.Start;
            this.End = output.End;
            this.Logs = output.Logs;           

        }
    }
}

预期结果是存储过程运行并将结果列表存储到 SearchInputResults。从那里,这些结果应该存储在另一个 DTO 中,以便在 return.

上传递

对于 EF,您将希望利用 Select() 将实体映射到您的 DTO,但您需要考虑 DTO 的整个结构。例如,"Logs" 数据结构将由什么组成?它是单个字符串值、字符串列表还是日志记录列表?

使用 Select() 你需要利用 属性 setter,而不是接受实体的构造函数。

所以这样的模式:

public class Entity
{ 
   public string Field { get; set; }
}

public class Dto
{ 
    public string Field { get; set; }
}

var dtos = context.Entities
    .Where(x => x.IsActive)
    .Select(x => new Dto
    {
        Field = x.Field
    })
    .ToList();

使用构造函数查看您的示例: public class Dto { public 字符串字段 { 得到;私有集; }

    public Dto(Entity entity)
    {
       Field = entity.Field;
    }
}

var dtos = context.Entities
    .Where(x => x.IsActive)
    .Select(x => new Dto(x))
    .ToList();

这不适用于 EF 和 Select。 EF 可以映射到对象,但只能通过属性和无参数构造函数。有一个破解需要注意,但如果你看到它,请避免:

var dtos = context.Entities
    .Where(x => x.IsActive)
    .ToList()
    .Select(x => new Dto(x))
    .ToList();

使用 select 之前的额外 ToList(),调用将起作用,因为 EF 将执行查询和 return 实体列表,然后 Select() 将作为 Linq2Object 查询执行。你应该避免这种情况的原因是因为 EF 将从实体 select all 属性,我们应该只拉回我们关心的属性。如果您的 Dto 构造函数群体开始迭代相关实体,也很容易陷入 lazy-load 性能陷阱。使用 Select 从实体和任何相关实体中仅加载您需要的字段,允许 EF 构建仅针对所需数据的高效查询,而无需任何延迟加载陷阱。

使用 AutoMapper,您可以通过设置从实体到 DTO 的映射然后利用 ProjectTo<Dto>().

来简化此操作

因此,如果您希望 DTO 表示结果(例如成功标志、错误消息)以及成功时的结果集合:

[Serializable]
// Our results container.
public class SearchResultsDTO
{
    public bool IsSuccessful { get; private set; } = false;
    public string ErrorMessage { get; private set; }
    public ICollection<SearchResultDTO> Results { get; private set; } = new List<SearchResultDTO>();

    private SearchResultsDTO() {}

    public static SearchResultsDTO Success(ICollection<SearchResultDTO> results)
    {
        var results = new SearchResultsDTO
        {
            IsSuccessful = true,
            Results = results
        };
        return results;
    }
    public static SearchResultsDTO Failure(string errorMessage)
    {
        var results = new SearchResultsDTO
        {
            ErrorMessage = errorMessage
        };
        return results;
    }
}

[Serializable]
public class SearchResultDTO
{
    public int ID {get; set;}
    public string Name {get; set;}
    public string Job {get; set;}
    public DateTime Start {get; set;}
    public DateTime End {get; set;}
    public ICollection<string> Logs {get; set;} = new List<string>();  
}

然后从 DbContext 填充这些:(在存储库内或读取数据的任何地方)

using (var context = new SearchContext())
{
    var results = context.Logs
        .Where(x => x.Name.Contains(sRequest))
        .Select(x => new SearchResultDTO
        {
            ID = x.ID,
            Name = x.Name,
            Job = x.Job,
            Start = x.Start,
            End = x.End,
            Logs = x.LogLines.Select(y => y.Line).ToList(),
        }).ToList();

     var resultDto = SearchResultsDTO.Success(results);
     return resultsDto;
}

这假设日志条目有作业、名称、开始、结束 date/times,然后是 "lines" 或要显示为 "Logs" 的条目列表。 (其中 Log table 有一个相关的 LogLine table 例如与一行或多行)这演示了如何利用 Select 不仅将日志记录映射到 DTO,而且将相关记录映射到字符串集合之类的东西,或者也可以完成其他 DTO 的集合。

一旦它 select 成为 DTO,我让它使用静态工厂方法填充容器 DTO 以填充成功读取或失败读取。 (例如,可以在异常处理程序中设置。)或者,您可以只新建一个容器 class 并填充属性,使用构造函数 /w 参数,或者只 return DTO 列表。 SearchResultsDTO 容器在 EF 查询中被引用。