.NET CORE:Dapper 映射多对多查询

Posted

技术标签:

【中文标题】.NET CORE:Dapper 映射多对多查询【英文标题】:.NET CORE: Dapper map many-to-many query 【发布时间】:2020-12-19 19:47:14 【问题描述】:

我正在尝试学习 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);

            
        

【问题讨论】:

在 StudentViewModel 构造函数中设置断点。我的猜测是每个 CourseModel 实例都会调用它。见dapper-tutorial.net/query 【参考方案1】:

在学习使用 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 );

【讨论】:

以上是关于.NET CORE:Dapper 映射多对多查询的主要内容,如果未能解决你的问题,请参考以下文章

dapper 多对多查询对象和对象列表

Core Data + RestKit 映射多对多关系?

EF Core中的多对多映射如何实现?

ef core中如何实现多对多的表映射关系

如何在 EF Core 中查询多对多关系

Asp.net Core中的多对多实现问题[重复]