【问题标题】:How to correctly store a number of results in a DTO?如何在 DTO 中正确存储多个结果?
【发布时间】:2019-05-07 00:04:49
【问题描述】:

我已将存储过程附加到数据库,该数据库应仅通过简单的搜索即可返回结果。查询被添加到我的实体并调用常规方法。我面临的问题是将这个过程的结果作为列表存储到特定的 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 中,以便在返回时传递出去。

【问题讨论】:

  • 您的搜索查询返回什么?确定返回记录类型后,您需要将每个项目的属性映射到 DTO 属性,例如result.Name = dto.Name。然后将List&lt;object&gt; Results 更改为List&lt;MyDTOtype&gt; ResultsAutoMapper 是帮助映射模型的有用工具。
  • 搜索应该返回与传递给它的字符串匹配的行。我正在研究自动映射器,但不确定实现需要什么。

标签: c# entity-framework asp.net-mvc-4 asp.net-web-api2


【解决方案1】:

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

使用Select(),您需要利用属性设置器,而不是接受实体的构造器。

这样的模式:

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();

用构造函数看你的例子: 公开课 Dto { 公共字符串字段 { 获取;私人套装; }

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

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

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

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

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

使用 AutoMapper,您可以通过设置从实体到 DTO 的映射然后利用 ProjectTo&lt;Dto&gt;() 来简化此操作。

因此,如果您希望 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;
}

这假定日志条目具有作业、名称、开始、结束日期/时间,然后是“行”列表或显示为“日志”的条目。 (其中 Log 表有一个相关的 LogLine 表,例如一行或多行)这演示了如何利用 Select 不仅将日志记录映射到 DTO,而且还将相关记录映射到类似的集合字符串或其他 DTO 的集合也可以完成。

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

【讨论】:

  • 有什么方法可以在不使用 select 语句的情况下将它与我创建的存储过程 _output.searchLog2(searchString) 结合起来?
  • 可能,尽管除了启动偶尔的批量操作之外,我根本不将 Sprocs 与 EF 一起使用,与实体无关。 EF 被设计为一个关系映射器,用于绑定对象并让它从 Linq 表达式组合 SQL 查询,以避免编写 Sprocs。
猜你喜欢
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 1970-01-01
  • 2020-03-09
  • 1970-01-01
  • 2011-10-13
相关资源
最近更新 更多