如何从EntityFramework查询复杂的结果集并在MVC中显示结果集。

时间:2012-07-25 15:50:10

标签: c# asp.net-mvc-3 linq razor entity-framework-4.1

我在MVC3,C#工作并使用Razor。我不会在一致的基础上使用MVC所以我不断重新学习东西...我想要一个显示学校列表(来自指定状态)的视图,其中包含学生的嵌套列表(来自该学校)中间名为'Bob'。

看起来很简单但到目前为止我无法找到解决方案。

Ex:VIEW

马里兰州的结果

我的第一所学校: - 比利鲍勃约翰逊 - 莎莉鲍勃辛普森 - 亚当鲍勃琼斯

另一所学校: - 阿诺德鲍勃史密斯 - Cathy Bob Powers - 珍妮鲍勃史密斯

其他学校: - 巴尼鲍勃爱德森 - Sue Bob Purdee - 艾伦鲍勃沃菲尔德

public class School
{ 
   public int SchoolId {get; set;} 
   public string Schoolname {get; set;} 
   public int StateId {get; set;} 
} 


public class Student
{ 
   public int StudentId {get; set;}
   public int SchoolId {get; set;} 
   public string Firstname {get; set;} 
   public string Middlename {get; set;} 
   public string Lastname {get; set;} 
} 


public class SchoolViewModel
{ 
   public int SchoolId {get; set;}
   public string Schoolname {get; set;}  
   public IEnumerable<Student> Bobs { get; set; }
} 

通过使用JOINS进行SELECT获取列表将为我提供一个数据集,需要额外的工作才能在VIEW中显示,如上图所示。我认为有一种方法可以以一种允许数据集像多维数组一样的方式获取嵌套的学生列表。但我没有找到这种方法的例子 - 让我觉得那不是那种方式......?如何以最佳使用LINQ / MVC / ViewModel等方式获取数据? :)

我正在尝试这样的事情 - 但不知道这是不是正确的方向 - 当我试图设置Bobs时它给了我一个错误。 :)

我收到如下错误: LINQ to Entities无法识别方法'System.Linq.IQueryable`1 [stuff] GetBobs(stuff)'方法,并且此方法无法转换为商店表达式。

  private IQueryable<SchoolViewModel> GetSchools(int StateId)
  {
        var query = from s in db.Schools
                    where s.State == StateId
                    orderby s.Schoolname
                    select new SchoolViewModel
                    {
            SchoolId = s.SchoolId,
                        Name = s.Name,
                        Bobs = GetBobs(s.SchoolId)
                    };
    var results = query;
        return results;
    }

    private IQueryable<Student> GetBobs(int id)
    {

        var query = from s in db.Students
                    where s.Middlename == 'Bob'
                    where s.SchoolId == id
                    select s;

        var results = query;
        return results;
    }

2 个答案:

答案 0 :(得分:2)

嗯,你总是可以为查询部分做这个,我猜这是你被绊倒的地方:

var schools = db.Schools
     .Where(x => x.State == "<Whatever>")
     .Select(x => new {
          School = x,
          Bobs = x.Where(y => y.MiddleName == "Bob")
     }).ToList();

List<Schools> schoolsView = new List<Schools>();
foreach(var x in schools)
{
     schoolsView.Add(new SchoolsViewModel(){
          //Set Properties here
          SchooldID = x.School.ID,
          SchoolName = x.School.Name,
          Students = x.Bobs.ToList() //You can project here if needed.
     };
}

return schoolsView;

然后对于您的视图,您可以通过多种方式执行此操作,但如果您具有固定输出的具体ViewModel,则它只是嵌套循环:

<ul>
@foreach(var m in Model)  //Assuming your model is a list of SchoolViewModels
{
     <li>@m.SchoolName
          <ul>
               @foreach(var s in m.Students)
               {
                    <li>@s.Name</li>
               }
          </ul>
     </li>
}
</ul>

您也可以通过String.Join(",", Model.Students)来输出列表,但这取决于您。

修改:额外澄清

您还需要更改模型,我不确定您使用的EF版本,但在EF4.1 +中,您可以指定导航属性以消除对显式连接条件的需要(即最终的正确方法)。

http://msdn.microsoft.com/en-us/library/bb738520.aspx

所以你的学校模型将成为:

public class School
{ 
   public int SchoolId {get; set;} 
   public string Schoolname {get; set;} 
   public int StateId {get; set;} 
   public virtual IList<Student> Students {get; set; }
} 

然后在您的数据库配置中(如果您使用的是流畅的,配置将是:

modelBuilder.Entity<School>()
     .HasMany(x => x.Students).WithRequired();

然后你获得了做的力量

db.Schools
    .Where(x => x.Name.Contains("Some Value"))
    .Include(x => x.Schools.Where(x => x.MiddleName.Contains("SomeValue")))
    .ToList();

这甚至使我的先前查询更简单,而无需使用模糊类型定义。

希望这个澄清有助于进一步。

答案 1 :(得分:1)

你可以尝试这样的东西来显示数据。

顶级视图:

@model SchoolViewModel
@using (Html.BeginForm()) 
{
    <fieldset>
        @Html.EditorFor(x => x.Bobs)
        <input type="submit" value="Save" />
    </fieldset>
}

然后,您可以使用编辑器模板进行显示。在以下URL创建它们:〜/ Views / Shared / EditorTemplates / Student.cshtml

@model Student
@Html.DisplayFor(x => x.StudentID)
@Html.DisplayFor(x => x.SchoolID)
@Html.DisplayFor(x => x.FirstName)
@Html.DisplayFor(x => x.MiddleName)
@Html.DisplayFor(x => x.LastName)

然后,您可以在生成的子列表中放置您想要的任何格式。 Bobs IEnumerable中的每个学生都将根据您在编辑器模板中定义的规则进行渲染。

就实际查询数据库而言,我会沿着这种模式创建某种存储库:

public interface IRepository<TEntity> where TEntity : class
{
    List<TEntity> FetchAll();
    IQueryable<TEntity> Query { get; }
    void Add(TEntity entity);
    void Delete(TEntity entity);
    void Save();
}  

具体实现如下:

public class SQLRepository<T> : IRepository<T> where T : class
{
    private DataContext db;
    public SQLRepository()
    {
        this.db = new TestDataContext();
    }
    public void Add(T entity)
    {
        db.GetTable(Of T)().InsertOnSubmit(entity)
    }
    public void Delete(T entity)
    {
        db.GetTable(Of T)().DeleteOnSubmit(entity)
    }
    public System.Collections.Generic.List<T> FetchAll()
    {
        return Query.ToList();
    }
    public System.Linq.IQueryable<T> Query {
        get { return db.GetTable<T>(); }
    }
    public void Save()
    {
        db.SubmitChanges()
    }
}