7

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

SqlDataReader从using创建对象的最佳方法是什么LINQ

注意:我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:从左连接填充对象
  2. DataTable 上的复杂 GROUP BY
4

5 回答 5

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

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

于 2013-07-15T09:06:07.057 回答
2

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

在这里,您可以找到我关于类似论点的答案之一。正如我每次所说,答案可能取决于您需要解决方案的上下文。据我所知,您不想使用 ORM,因此一个干净且基本的解决方案可能是:

  1. 使用SqlDataReaderToObject
  2. 使用IDbComannd 和 IDataReader 的扩展方法

其中每一个都是基础 ADO.NET 对象的“助手” 。正如我之前所说,使用这样的解决方案需要一些限制,例如对象字段或属性名称等。希望这可以帮助。

于 2013-08-02T12:31:09.530 回答
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()
                                     });
        }
于 2013-07-30T06:39:20.470 回答
1

你真的应该考虑使用dapper。它支持存储过程,正如页面所示,极其简单的 dapper 调用和过度设计的手工映射解决方案之间的性能差异可以忽略不计:

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

  • 手工编码(使用 SqlDataReader)47 毫秒
  • Dapper ExecuteMapperQuery 49ms
于 2013-07-30T17:42:43.197 回答
0

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

我有一个基于实体框架定义动态构建对象和关系的项目。这更有活力。

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

于 2013-08-05T09:25:57.583 回答