1

我正在尝试投影相关数据,但不断出现错误。

我有一个项目列表,每个项目可能有多个基线集(或没有),每个基线包含多个里程碑。计划的项目列表应包含一个属性,该属性包含最近设置的基线中的特定里程碑。

我的模型通过 EFCore 在 SQL 中:

public class Project
{
    public int ProjectID { get; set; }
    public string Name { get; set; }
    public ICollection<Baseline> Baselines { get; set; }
}

public class Baseline
{
    public int BaselineID { get; set; }
    public int ProjectID { get; set; }
    public Project Project { get; set; }
    public string Name { get; set; }
    public DateTime DateSet {get; set;}
    public string Description { get; set; }
    public ICollection<BaselineDate> BaselineDates { get; set; }
}

public class BaselineDate
{
    public int BaselineDateID { get; set; }
    public int BaselineID { get; set; }
    public Baseline Baseline { get; set; }
    public int MilestoneTypeID { get; set; }
    public MilestoneType MilestoneType { get; set; }
    public DateTime Date { get; set; }
    public string Comment { get; set; }
}

在我的控制器中,我定义了投影类:

public class ProjectInfo
{
    public int ProjectID { get; set; }
    public string ProjectName { get; set; }
    public DateTime? ProjectStart { get; set; }
}

public IList<ProjectInfo> ProjectInfoList { get; set; }

然后在一个函数中,我尝试使用 efcore 来查询模型:

ProjectInfoList = await _context.Project
     .Where(project => project.Branch == Branch)
     .Select(project => new ProjectSummary
         {
             ProjectID = project.ProjectID,
             ProjectName = project.Name,
             ProjectStart = project.Baselines
                 .DefaultIfEmpty(new Baseline { BaselineDates = new List<BaselineDate>() })
                 .OrderByDescening(b => b.DateSet)
                 .FirstOrDefault()
                 .BaselineDates
                 .Where(d => d.Comment == "Project Start")
                 .FirstOrDefault()
                 .Date
          }
       .AsNoTracking()
       .ToListAsync();

只要每个项目都有一个基线,这就可以正常工作。但是,当存在没有基线的项目时,会引发空异常。

ArgumentNullException:值不能为空。参数名称:source System.Linq.Enumerable.Where(IEnumerable source, Func predicate)

我尝试添加 .DefaultIfEmpty(new Baseline()) 但它会引发更多异常。

4

1 回答 1

1

请记住,实体框架将整个 LINQ 表达式转换为 SQL(好吧,更准确地说,尝试这样做)。由于 SQL 中没有空引用的概念,您可以安全地使用在 C# 代码(或:LINQ-to-objects)中会引发空引用异常的表达式。

但除此之外,可以重写有问题的子查询,这样即使在 LINQ-to-objects 中,如果集合属性不为 null,它也不会引发异常:

ProjectInfoList = await _context.Project
     .Where(project => project.Branch == Branch)
     .Select(project => new ProjectSummary
         {
             ProjectID = project.ProjectID,
             ProjectName = project.Name,
             ProjectStart = (from bl in project.Baselines
                from bd in bl.BaselineDates
                where bd.Comment == "Project Start"
                orderby bl.DateSet descending, bd.Date descending
                select (DateTime?)bd.Date).FirstOrDefault()
          }
       .AsNoTracking()
       .ToListAsync();

我在查询语法中这样做是为了更好的可读性。该from ... from构造采用SelectMany方法语法。SelectMany语法,当需要来自父母和孩子的数据时(bl.DateSet, bd.Date),非常尴尬。

于 2018-12-17T20:53:26.340 回答