【问题标题】:Creating nested child entities创建嵌套子实体
【发布时间】:2020-03-05 13:58:40
【问题描述】:

我正在尝试对 SQL 服务器进行查询,并将结果转换为我根据我希望如何将结果转换为我的 API 的 JSON 数据而设计的模型。

这是我正在尝试创建并使用数据填充的 JSON 模型

public class JsonProject 
{
   public int ProjectId { get; set; }
   public int ProjectName { get; set; }
   public List<JsonJob> Jobs { get; set; }
}
public class JsonJob
{
   public int JobId { get; set; }
   public int JobName { get; set; }
   public List<JsonResource> Resources { get; set; }
}
public class JsonResource
{
   public int ResourceId { get; set; }
   public DateTime DateStart { get; set; }
   public DateTime DateEnd { get; set; }
}

这是我进行向控制器返回数据的查询的方法

//Param in is "resourceId"
var query = from rb in db.ResourceBooking
            join rrb in db.ResourceRoleBooking on rb.IdResourceBooking equals rrb.IdResourceBooking
            join job in db.Job on rrb.IdJob equals job.IdJob
            join project in db.Project on job.IdProject equals project.IdProject
            where rb.IdAddress == resourceId //all resources is stored as an address
            orderby rrb.DateStart
            group new {
              rb,
              rrb,
              job,
              project
            } by new {
              ProjectId = project.IdProject,
              ProjectName = project.Name
            } into g
            select new JsonProject {
              ProjectId = g.Key.ProjectId,
              ProjectName = g.Key.ProjectName,
              Jobs = g.Select( x => new JsonJob { // The Problem
                JobId = x.job.Id,
                JobName = x.job.Name,
                Resources = null  // null for now until I get JsonJob working
              }).ToList()
            };

一个工作属于一个项目,一个工作首先将资源预订为 ResourceRoleBooking 中的角色,然后这些角色链接到 ResourceBooking 中的特定资源(人类),我可以在其中搜索用户 ID。

当用户想要查看他计划执行的项目时使用该查询。连接的顺序基于将 WHERE 子句放在连接的顶部,我相信这将有助于提高性能(?)

我尝试将数据组合在一起,首先是针对每个项目。当我尝试在 JsonProjects 中创建新的 JsonJobs 时遇到了麻烦。

当我尝试运行此代码时,它会导致 InvalidOperationException

)' 无法翻译。以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。请参阅https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。

-为了进行故障排除,我尝试将 JsonProject.Jobs 转换为整数并使用 Jobs = g.Sum(x =&gt; x.job.Id) 工作。然后我可以看到有多份工作的项目数量更多。 - 如果我尝试使用匿名类型(select new { ProjectId = g.Key.ProjectId, JobId = g.Select(x =&gt; new { JobName = x.job.Name }).ToList() 它不会返回任何结果。

【问题讨论】:

  • 该错误意味着 EF 无法将您的查询转换为 SQL。是否计算了源对象(不是 JSON*)中的任何属性?你能告诉我们课程ResourceBookingResourceRoleBookingJobProject吗?

标签: c# sql .net linq


【解决方案1】:

我认为这个关于包含与连接的问题将有助于对您的问题提供一些见解。在您的情况下,我会为 JsonJob 和最终的 JsonResources 使用包含,以便它们保持正确的结构。

LINQ Include vs Join. Are they equivalent?

编辑:我的评论已格式化

查看此文档 https://docs.microsoft.com/en-us/ef/ef6/querying/related-data

有这个例子

var blog2 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include("Posts")
                       .FirstOrDefault();

所以你的可能看起来像这样

            .Include( x => x.JsonJob)
            .Select(JobId = x.job.Id,
                JobName = x.job.Name,
                Resources = null
              ).ToList()

【讨论】:

  • 看起来你是对的,我希望在项目中包含作为嵌套孩子的工作。但是我看没办法解释Include方法两个表之间的关系?我对复杂性感到困惑,因为我希望 Project 成为父级,但必须通过作业找到 ResourceBooking 表以制作 WHERE 子句。我是否应该加入工作表以便能够执行 WHERE,然后将其包含在内?以及如何像在 join(on [key] equals [key]) 中那样指定 Project 和 Job 之间的关系
  • 对不起,不得不重写那条评论。看看我的编辑。假设您在表创建文件中定义了多对一关系,则您不需要选择,因为此对象基于此。
  • 但这一切都是基于让模型解释模型之间的关系,对吧?由于数据库的复杂性,到目前为止我还没有在项目中这样做,并且希望避免这种情况,而是直接手动将每个查询转换为模型。这适用于join,因为您有onequals,但include 似乎不存在?如果我想使用 include,我必须创建正确的模型来解释表之间的关系?
【解决方案2】:

按照我想要的方式检索数据的解决方案是这样的:

context.Project
  .Where(proj => proj.Job.Any(
    jo => jo.ResourceRoleBooking.Any(
      resrb => resrb.DateEnd >= DateTime.Now.AddDays(-60) 
               && resrb.ResourceBooking.Any(
        reb => reb.IdAddress == idAdr
  ))))
  .OrderBy(x => x.StartDate)
  .Select(x => new JsonProject
  {
    ProjectId = x.IdProject,
    ProjectName = x.Name,
    Jobs = x.Job
      .Where(j => j.ResourceRoleBooking.Any(
        rrb => rrb.ResourceBooking.Any(
          rb => rb.IdAddress == idAdr
        )
      ))
      .Select(j => new JsonJob
      {
        JobId = j.IdJob,
        JobName = j.Caption,
        Resources = j.ResourceRoleBooking.SelectMany(
                      rrb => rrb.ResourceBooking,
          (parent, child) => new JsonResource
          { 
            DateStart = parent.DateStart,
            DateEnd = parent.DateEnd
          }).ToList()
      }).ToList()
  });

我不能像我最初想的那样使用分组,但最终在每个对象中执行了新的查询,我重复了 Where 语句,只选择了我想要的结果。

我还没有研究过它的性能,我认为在彼此之间有这么多 Where 子句的情况非常糟糕,但是一旦我对此进行了更多测试,我会报告回来。

【讨论】:

    猜你喜欢
    • 2016-10-25
    • 2019-06-26
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多