问题描述
我正在尝试学习Dapper,并且在尝试将查询映射到多对多关系时遇到了麻烦。在这种情况下,我有三个模型和各自的表,CourseModel,StudentCourseModel和Studentviewmodel。
我正在尝试创建一个详细视图,您可以在其中显示学生的所有课程。这就是我试图访问数据的方式,但是由于某种原因,即使学生参加的课程多于课程,但在学生课程列表中仅设置了一个“课程”记录。我究竟做错了什么?谢谢!
课程模型
public class CourseModel
{
public int Id { get; set; }
public string CourseCode { get; set; }
public string CourseName { get; set; }
public string CourseDescription{ get; set; }
}
StudentCourseModel
public class StudentCourseModel
{
public int Id { get; set; }
public int StudentId { get; set; }
public int CourseId { get; set; }
}
Studentviewmodel
public class Studentviewmodel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public List<CourseModel> Courses { get; set; }
public Studentviewmodel()
{
Courses = new List<CourseModel>();
}
}
public async Task<IActionResult> Details(int id)
{
using (IDbConnection cnn = new sqlConnection("Data Source=(localdb)\\MSsqlLocalDB;Initial Catalog=SchoolSystemDB;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultisubnetFailover=False"))
{
var p = new
{
Id = id
};
string sql = $@"select dbo.Students.*,dbo.Courses.*
from dbo.Students
INNER JOIN[dbo].[StudentCourses] ON dbo.StudentCourses.StudentID = dbo.Students.Id
INNER JOIN[dbo].[Courses] ON dbo.Courses.Id = dbo.StudentCourses.CourseId
WHERE dbo.Students.Id = @Id";
Studentviewmodel student = cnn.Query<Studentviewmodel,CourseModel,Studentviewmodel>(sql,(Studentviewmodel,CourseModel) =>
{
Studentviewmodel.Courses.Add(CourseModel);
return Studentviewmodel;
},p).First();
return View(student);
}
}
解决方法
当我学会使用dapper时,我还遇到了多对多映射的问题。
对我来说,以下程序证明是有用的:
构建映射函数时,您可以在数据库建模工具(例如 SSMS )中执行一次查询,以查看查询数据的结构。
然后,您可以想象对于查询结果中返回的每一行,都将执行映射功能。因此,您需要跟踪映射功能已经处理的数据。传递给函数的StudentViewModel实例代表当前行之一,这说明了为什么只附加一门课程。
要跟踪学生,可以在映射功能之外使用查找词典。 (无法在atm下测试示例)
var studentLookup = new Dictionary<int,StudentViewModel>();
var res = cnn
.Query<StudentViewModel,CourseModel,StudentViewModel>(
sql,(svm,cm) =>
{
// Check if the student was already processed; if so,retrieve the reference
if (!studentLookup.TryGetValue(svm.Id,out var student))
{
student = svm;
studentLookup.Add(svm.Id,student);
}
// add course to the student that is assigned with the current record
if (svm.Courses == null)
{
svm.Courses = new List<CourseModel>();
}
if (svm.Courses.All(x => x.Id != cm.Id))
{
svm.Courses.Add(cm);
}
return svm;
},new { Id = id });