如何在复杂的表结构中加载MVC中的相关数据

时间:2012-07-27 22:51:43

标签: asp.net-mvc-3 linq dbcontext

我有几节课,为简洁起见我会缩短。下面列出了与此问题相关的相关属性/字段。

public class AcademicYear
{
    [Key]
    public int AcademicYearId { get; set; }
}

public class Division
{
    public Division()
    {
        this.CareerFields = new HashSet<CareerField>();
    }

    [Key]
    public int    DivisionId     { get; set; }

    // Foreign Keys
    public int    AcademicYearId { get; set; }

    // Navigation Properites
    public virtual AcademicYear AcademicYear { get; set; }

    public virtual ICollection<CareerField> CareerFields { get; set; }
}

public class CareerField
{
    public CareerField()
    {
        this.Clusters    = new HashSet<Cluster>();
    }

    [Key]
    public int    CareerFieldId   { get; set; }

    // Foreign Keys
    public int    AcademicYearId  { get; set; }
    public int    DivisionId      { get; set; }


    // Navigation Properties
    public virtual AcademicYear AcademicYear { get; set; }
    public virtual Division     Division     { get; set; }

    public virtual ICollection<Cluster>    Clusters    { get; set; }
}

public class Cluster
{
    public Cluster()
    {
        this.CareerFields = new HashSet<CareerField>();
    }

    [Key]
    public int ClusterId { get; set; }
    {
        // Foreign Keys
        public int    AcademicYearId { get; set; }

        // Navigation Properties
        public virtual AcademicYear AcademicYear { get; set; }

        public virtual ICollection<CareerField> CareerFields { get; set; }
    }
}

public class Pathway
{
    public Pathway()
    {
        this.CareerMajors = new HashSet<CareerMajor>();
    }

    [Key]
    public int    PathwayId      { get; set; }

    // Foreign Keys
    public int    AcademicYearId { get; set; }
    public int    ClusterId      { get; set; }

    // Navigation Properties
    public virtual AcademicYear AcademicYear { get; set; }
    public virtual Cluster      Cluster      { get; set; }

    public virtual ICollection<CareerMajor> CareerMajors { get; set; }
}

public class CareerMajor
{
    public CareerMajor()
    {
        this.Courses        = new HashSet<Course>();
    }

    [Key]
    public int    CareerMajorId     { get; set; }
    public string FirstYearOffered  { get; set; }

    // Foreign Keys
    public int    AcademicYearId    { get; set; }
    public int    PathwayId         { get; set; }

    // Navigation Properties

    [HiddenInput(DisplayValue = false)]
    public virtual AcademicYear      AcademicYear      { get; set; }
    public virtual Pathway           Pathway           { get; set; }

    public virtual ICollection<Course>         Courses        { get; set; }

}

public class Course
{
    public Course()
    {
        this.CareerMajors  = new HashSet<CareerMajor>();
    }

    [Key]
    public int    CourseId       { get; set; }

    // Foreign Keys
    public int    AcademicYearId { get; set; }
    public int?   InstructorId   { get; set; }

    // Navigation Properties
    public virtual ICollection<CareerMajor>  CareerMajors  { get; set; }

    public virtual AcademicYear AcademicYear { get; set; }
}

我还有一个ViewModel类来为我的控制器加载所有这些

public class CMSIndex
{
    public IEnumerable<Division> Divisions { get; set; }
    public IEnumerable<CareerField> CareerFields { get; set; }
    public IEnumerable<Cluster> Clusters { get; set; }
    public IEnumerable<Pathway> Pathways { get; set; }
    public IEnumerable<CareerMajor> CareerMajors { get; set; }
    public IEnumerable<Course> Courses { get; set; }
}

我有一个razor cshtml页面(自动CRUD定义的索引页面),我从该部门开始,我可以加载相关的CareerFields。但是,当我尝试加载群集时,我收到错误消息

  '/'应用程序中的服务器错误。   值不能为空。   参数名称:source    描述:执行当前Web请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

     

异常详细信息:System.ArgumentNullException:值不能为null。   参数名称:source

这是我在控制器中的索引方法(注意注释掉的行也是我试过的)

public ViewResult Index(Int32? divisionID, Int32? careerFieldID, Int32? clusterID, Int32? pathwayID, Int32? careerMajorID, Int32? courseID)
    {
        var viewModel = new CMSIndex();

        viewModel.Divisions = db.Divisions
            .Include(d => d.AcademicYear)
            .Include(d => d.CareerFields)//
            .Include(d => d.CareerFields.Select(cf => cf.Clusters))
            //.Select(c => c.Clusters.Select(cl => cl.Pathways.Select(p => p.CareerMajors.Select(cm => cm.Courses)))))
            .OrderBy(d => d.DivisionName);

        if (divisionID != null)
        {
            ViewBag.DivisionID = divisionID.Value;
            viewModel.CareerFields = viewModel.Divisions.Where(d => d.DivisionId == divisionID.Value).Single().CareerFields;
        }

        if (careerFieldID != null)
        {
            ViewBag.careerFieldID = careerFieldID.Value;
            //viewModel.Clusters = viewModel.CareerFields.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;
            //viewModel.Clusters = viewModel.CareerFields.SelectMany(cf => cf.Clusters);
            viewModel.Clusters = viewModel.CareerFields.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;
        }

        return View(viewModel);
    }

我正在关注加载相关数据的Contoso教程。我似乎能够加载1:m的关系,但我不确定如何使用m:m(例如CareerFields和Clusters)。

并且,我确实有一个初始化程序,它已经加载了数据以便我传递一个ID(例如,careerFieldID)。

抛出异常的地方是:

viewModel.Clusters = viewModel.CareerFields.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;

每个评论的变体。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

不是说这是问题,但你检查的值是不是空?在行

viewModel.Clusters = viewModel.CareerFields
    .Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;

viewModel.CareerFields是否可能为空?

正如一些旁注:

  • 当你有空的时候进行空检查,最好使用他们的HasValue方法,例如。

    if (divisionID.HasValue)
    {
        ...
    }
    
  • 使用Single()可能有点气质,如果不存在元素或存在多个元素,则可以抛出异常。 First()可以用来处理多个(但如果没有匹配就会抛出),SingleOrDefault()将处理零或一个结果,而FirstOrDefault()将处理大多数事情。

  • 您可以通过将lambda放在单个例如

    中来保存表达式
    viewModel.CareerFields = viewModel.Divisions
        .Single(d => d.DivisionId == divisionID.Value).CareerFields;
    

编辑:我认为您遇到的问题与This Answer中的问题相同,您是否可以尝试更改类集合,以便在get时为null时初始化。例如,分部

public class Division
{
    [Key]
    public int    DivisionId     { get; set; }

    // Foreign Keys
    public int    AcademicYearId { get; set; }

    // Navigation Properites
    public virtual AcademicYear AcademicYear { get; set; }

    private ICollection<CareerField> careerFields;
    public virtual ICollection<CareerField> CareerFields { 
        get { return careerFields ?? (careerFields = new HashSet<CareerField>()); }
        set { careerFields = value; } 
    }
}

无论如何,这实际上是我首选的方法,这对你的代码强加了它自己的问题,因为CareerFields为null意味着对于给定的分区,没有相关的CareerFields。这意味着当您的Single()调用被命中时,它将抛出异常The source contains no elements,因为CareerFields将包含一个空的hashset。这可以通过更改为SingleOrDefault()来解决。