从存储过程结果创建对象

时间:2013-07-15 08:02:52

标签: c# sql-server linq stored-procedures

我们有一个现有的SQL Server存储过程,其中包含以下查询。我们需要根据查询结果在以下类设计中创建Student个对象的集合。

使用SqlDataReaderLINQ创建对象的最佳方法是什么?

注意:我只使用SqlDataReader;没有ORM

查询

SELECT 
    S.StudentID, S.StudentName, E.ExamID, E.ExamName, SE.Mark 
FROM 
    StudentExam SE
INNER JOIN 
    Student S ON S.StudentID = SE.StudentID
INNER JOIN 
    Exam E ON E.ExamID = SE.ExamID 

public class ExamMark
{
    public int ExamID { get; set; }
    public string ExamName { get; set; }
    public int Mark { get; set; }
}

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public List<ExamMark> examResults { get; set; }
}

SqlDataReader

   SqlDataReader reader = command.ExecuteReader();
   if (reader.HasRows)
   {
      while (reader.Read())
      {

      }
   } 

参考

  1. LINQ: Fill objects from left join
  2. Complex GROUP BY on DataTable

5 个答案:

答案 0 :(得分:5)

好吧,我不会那样做,

我有两个陈述

-- Student Statement
SELECT
             S.StudentID,
             S.StudentName
    FROM
             Student S
    WHERE
             EXISTS (
              SELECT * FROM StudentExam SE WHERE SE.StudentID = S.Student.ID);

-- Exam Statement
SELECT
            SE.StudentID,
            E.ExamID,
            E.ExamName,
            SE.Mark 
    FROM
            StudentExam SE
        JOIN
            Exam E
                ON E.ExamID = SE.ExamID;

然后,我有一个执行此功能的功能

private IEnumerable<Tuple<int, ExamMark>> GetMarks()
{
    ... setup the exam command here
    var reader = examCommand.ExecuteReader();
    while (reader.Read())
    {
        yield return Tuple.Create(
            reader.GetInt32(0),
            new ExamMark
                {
                    reader.GetInt32(1),
                    reader.GetString(2),
                    reader.GetInt32(3)
                });
    }
}

然后我有这个函数来调用,

private IEnumerable<Student> GetStudents()
{
    var resultLookup = GetMarks().ToLookup(t => t.Item1, t => t.Item2);

    ... setup the student command here
    var reader = studentCommand.ExecuteReader();
    while (reader.Read())
    {
        var studentId = reader.GetInt32(0);
        yield return new Student
                {
                    studentId,
                    reader.GetString(1),
                    resultLookup[studentId].ToList()
                });
    }
}

如果需要,可以在一个存储过程中完成所有操作并返回多个结果集。

答案 1 :(得分:2)

这应该做的工作:

using (SqlDataReader reader = command.ExecuteReader())
        {
            var records = (from record in reader.Cast<DbDataRecord>()
                           select new
                           {
                               StudentID = record.GetInt32(0),
                               StudentName = record.GetString(1),
                               ExamID = record.GetInt32(2),
                               ExamName = record.GetString(3),
                               Mark = record.GetInt32(4)
                           })
                           .GroupBy(r => new { StudentID = r.StudentID, StudentName = r.StudentName })
                           .Select(
                                     r => new Student
                                     {
                                         StudentID = r.Key.StudentID,
                                         StudentName = r.Key.StudentName,
                                         examResults = r.Select(e => new ExamMark
                                         {
                                             ExamID = e.ExamID,
                                             ExamName = e.ExamName,
                                             Mark = e.Mark
                                         }).ToList()
                                     });
        }

答案 2 :(得分:2)

我认为您的问题的重要性在于从DataReader创建对象(在本例中为SqldataReader)。

Here你可以找到我对类似论点的一个答案。正如我每次所说,答案可能取决于您需要解决方案的上下文。据我所知,你不想使用ORM,所以一个干净而基本的解决方案可能是:

  1. 使用SqlDataReaderToObject
  2. 使用Extension methods for IDbComannd and IDataReader
  3. 每个都是基于ADO.NET对象的“helpers”。正如我之前所说,使用类似的解决方案需要一些限制,例如对象字段或属性名称,等等。 希望这可以帮助。

答案 3 :(得分:1)

您应该考虑使用dapper。它supports stored procedures并且如页面所示,极其简单的短小调用和过度设计的手绘映射解决方案之间的性能差异可以忽略不计:

  

SELECT映射超过500次迭代的性能 - POCO序列化

     
      
  • 手动编码(使用SqlDataReader)47ms
  •   
  • Dapper ExecuteMapperQuery 49ms
  •   

答案 4 :(得分:0)

使用ADO.Net Entity框架和类似SPTE的方法(Stored Proc To Enity)可用于构建对象。

我有一个Project,它基于Entity Framework定义动态构建对象和关系。这更具活力。

我可以在code.google.com上分享代码。