EFCore:查询多个相关数据

时间:2018-12-17 11:01:26

标签: razor entity-framework-core

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

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

我的模型通过EFCore使用SQL:

private fun <T> any(): T {
    Mockito.any<T>()
    return uninitialized()
}
private fun <T> uninitialized(): T = null as T

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

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; }
}

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

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

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

只要每个项目都有一个基准,此方法就可以正常工作。但是,当存在没有基准的项目时,将引发null异常。

  

ArgumentNullException:值不能为null。   参数名称:来源   System.Linq.Enumerable.Where(IEnumerable源,Func谓词)

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

1 个答案:

答案 0 :(得分:1)

请记住,Entity Framework将整个LINQ表达式转换为SQL(更准确地说,是 try 来做到这一点)。由于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构造的方法语法为SelectManySelectMany的语法在需要父级和子级都需要数据(bl.DateSet, bd.Date)时非常尴尬。

相关问题