从存储过程中创建对象的结果
本文关键字:结果 创建对象 过程中 存储 存储过程 | 更新日期: 2023-09-27 18:22:16
我们有一个带有以下查询的现有SQL Server存储过程。在下面的类设计中,我们需要根据查询的结果创建一个Student
对象的集合。
使用LINQ
从SqlDataReader
创建对象的最佳方式是什么?
注意:我只使用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())
{
}
}
参考
- LINQ:从左联接填充对象
- DataTable上的复杂GROUP BY
好吧,我不会那样做的,
我要两份报表
-- 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()
});
}
}
如果需要,可以在一个存储过程中完成所有操作,并返回多个结果集。
这应该完成以下工作:
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()
});
}
我认为您的问题最重要的是从DataReader(在本例中为SqldataReader
)创建对象。
在这里,你可以找到我关于类似论点的一个答案。正如我每次所说,答案可能取决于您需要解决方案的上下文。正如我所理解的,你不想使用ORM,所以一个干净而基本的解决方案可以是:
- 使用SqlDataReaderToObject
- 使用IDbComand和IDataReader的Extension方法
其中每一个都是基础ADO.NET对象上的"助手"。正如我之前所说,使用这样的解决方案需要一些限制,例如对象字段或属性名等等。希望这能有所帮助。
您真的应该考虑使用dapper。它支持存储过程,正如页面所示,极其简单的dapper调用和过度设计的手动映射解决方案之间的性能差异可以忽略不计:
SELECT映射在500次迭代中的性能-POCO序列化
- 手动编码(使用SqlDataReader)47ms
- Dapper ExecuteMapperQuery 49ms
使用ADO.Net实体框架和类似SPTE(存储过程到Enity)的方法可以用来构建对象。
我有一个基于实体框架定义动态构建对象和关系的项目。这更具活力。
我可以在code.google.com.