Multi-Mapper в Dapper едно към много отношения

Опитвам се да получа стойността на моята база данни с връзка едно към много имам обекта си по този начин

Студент

[Table("Student")]
    public class Student  : IStudent
    {    

        public int Id { get; set; }
        public string Lastname { get; set; }
        public string FirstMidName { get; set; }
        public DateTime? EnrollmentDate { get; set; }

        [Write(false)]
        public IEnumerable<Enrollment> Enrollments { get; set; }
    }

Записване

[Table("Enrollment")]
    public class Enrollment
    {
        public int Id { get; set; }
        public int CourseId { get; set; }
        public int StudentId { get; set; }
        public string Grade { get; set; }
        public virtual Course Course { get; set; }
        public virtual Student Student { get; set; }
    }

курс

[Table("Course")]
public class Course
{   
    public int Id { get; set; }
    public string Title { get; set; }
    public int Credits { get; set; }
    public virtual IEnumerable<Enrollment> Enrollments { get; set; }
}

Ето моят елегантен код

_connection = Connect.GetOpenConnection();
        const string query = @"SELECT * FROM Student stu where id = @id " +
                             "SELECT * FROM Enrollment enr WHERE enr.StudentId in (SELECT id FROM Student stu where id = @id) " +
                             "SELECT * FROM Course cou WHERE cou.Id in (SELECT CourseId from Enrollment where StudentId = @id)";

        var result = _connection.QueryMultiple(query, new { id = id })
            .Map<Student, Enrollment, Course, int>(
                student => student.Id,     
                enrollment => enrollment.StudentId,
                course=>course.Id,
                (student, enrollments) => student.Enrollments = enrollments ,
                (student, courses) => student.Enrollments.ForEach(s=>courses.ForEach(x=>s.Course.Title = x.Title) )
            ).FirstOrDefault();

според инструкцията Тук Всичко, което трябва е да разширя йерархията на 3 нива, но не мога да го накарам да работи

ето го моя GridReader с картограф

public static IEnumerable<TFirst> Map<TFirst, TSecond, TThird, TKey>
        (
        this SqlMapper.GridReader reader,
        Func<TFirst, TKey> firstKey,
        Func<TSecond, TKey> secondKey,
        Func<TThird, TKey> thirdKey,
        Action<TFirst, IEnumerable<TSecond>> addSecond,
        Action<TFirst, IEnumerable<TThird>> addThird
        )
    {
        var result = reader.Read<TFirst>().ToList();

        var secondMap = reader
            .Read<TSecond>()
            .GroupBy(s=>secondKey(s))
            .ToDictionary(g => g.Key, g => g.AsEnumerable());

        var thirdMap = reader
           .Read<TThird>()
           .GroupBy(t => thirdKey(t))
           .ToDictionary(g => g.Key, g => g.AsEnumerable());     


        foreach (var item in result)
        {
            IEnumerable<TThird> third;
            if (thirdMap.TryGetValue(firstKey(item), out third))
            {
                addThird(item, third);
            }

            IEnumerable<TSecond> second;
            if (secondMap.TryGetValue(firstKey(item), out second))
            {
                addSecond(item, second);
            }

        }



        return result.ToList();
    }

когато стартирам приложението си, тук е резултатът с id от 1 забележка, че заглавието на курса няма стойност. Надявам се, че можете да ми помогнете, благодаря. неуспешно

АКТУАЛИЗАЦИЯ 1

Забелязвам, че тук получавам нулевата стойност, тя не влиза в оператора if

IEnumerable<TSecond> second;
        if (secondMap.TryGetValue(firstKey(item), out second))
        {
            addSecond(item, second);
        }

АКТУАЛИЗАЦИЯ 2

Решавам проблема, ето какво правя

var ctr = 0;
        var mapped2 = conn.QueryMultiple(query, new {id})
            .Map<Student, Enrollment, Course, int>(
                student => student.StudentId,
                enrollment => ctr = enrollment.StudentId,
                course=>course.CourseId = ctr,
                ((student, enrollments) => { student.Enrollments = enrollments; }),
                ((student, courses) => courses.ToList().ForEach(s=> student.Enrollments.ToList().ForEach(x=>x.Course = new Course
                {
                    Title = s.Title
                }))));

забележете, че добавих ctr, за да получа стойността на CourseId в enrollment => ctr = enrollment.StudentId. Добре сега се сблъсквам с друг проблем, как да получа стойността на courses тук е моят код

((студент, курсове) => courses.ToList().ForEach(s=> student.Enrollments.ToList().ForEach(x=>x.Course = new Course { Title = s.Title }))

получавам само последната стойност


person armory09    schedule 31.08.2015    source източник
comment
"SELECT * FROM Course cou WHERE cou.Id in (SELECT CourseId from Enrollment where StudentId = 1)"; Това трябва ли да е where StudentId = @id?   -  person Rob    schedule 31.08.2015
comment
Освен това вашият код дори не трябва да се компилира: student.Enrollments.ForEach(s=>courses.ForEach - Вашето записване има само един курс, така че трябва да бъде student.Enrollments.ForEach(c => c.Title = "Some course...");   -  person Rob    schedule 31.08.2015
comment
@Rob, прав си, трябва да е where StudentId = @id печатна грешка, не получих никаква грешка, когато се опитам да стартирам приложението си, вместо това получавам null стойност в курса, вижте екранната снимка   -  person armory09    schedule 31.08.2015


Отговори (1)


Ето как разрешавам проблема си

Като горните подробности за АКТУАЛИЗАЦИЯ 2 добавих променлива ctr, за да получа стойността на CourseId от Enrollment и да премина към Course, за да получа правилната стойност. След това се сблъсквам с друг проблем как да предам стойността на Course от Student.Enrollment.Course ето как го разбрах.

Създавам променлива var enrollLst = new List<Enrollment>();, за да задържа стойността на Enrollment от първото действие

((student, enrollments) =>
                {
                    enrollLst = enrollments.ToList();
                }),

Второ действие

((student, courses) =>
                {
                    var ctrId = 0;  
                    courses.ToList().ForEach(cour =>
                    {
                        if (cour != null)
                        {
                            enrollLst[ctrId].Course = cour;
                            ctrId++;
                        }
                        else
                        {
                            enrollLst[ctrId].Course = null;
                            ctrId++;
                        }   
                    });
                    student.Enrollments = enrollLst;
                })).FirstOrDefault(); 

по-долу е целият ми код

_connection = Connect.GetOpenConnection();
        const string query = "SELECT * from Student stu where StudentId = @id  " +
                             "SELECT * from Enrollment enr where enr.StudentId in ( SELECT StudentId from Student stu where Studentid = @id)  " +
                             "SELECT * FROM Course cou WHERE cou.CourseId in (SELECT CourseId from Enrollment where StudentId = @id)";

        var enrollLst = new List<Enrollment>();
        var ctr = 0;
        var result = _connection.QueryMultiple(query, new { id })
            .Map<Student, Enrollment, Course, int>(
                student => student.StudentId,
                enrollment => ctr = enrollment.StudentId,
                course => course.CourseId = ctr,
                ((student, enrollments) =>
                {
                    enrollLst = enrollments.ToList();
                }),
                ((student, courses) =>
                {
                    var ctrId = 0;  
                    courses.ToList().ForEach(cour =>
                    {
                        if (cour != null)
                        {
                            enrollLst[ctrId].Course = cour;
                            ctrId++;
                        }
                        else
                        {
                            enrollLst[ctrId].Course = null;
                            ctrId++;
                        }   
                    });
                    student.Enrollments = enrollLst;
                })).FirstOrDefault(); 

GridReader с картограф, разширен с йерархия от 3 нива, както е указано тук

public static IEnumerable<TFirst> Map<TFirst, TSecond, TThird, TKey>
        (
        this SqlMapper.GridReader reader,
        Func<TFirst, TKey> firstKey,
        Func<TSecond, TKey> secondKey,
        Func<TThird, TKey> thirdKey,
        Action<TFirst, IEnumerable<TSecond>> addSecond,
        Action<TFirst, IEnumerable<TThird>> addThird
        )
    {
        var result = reader.Read<TFirst>().ToList();

        var secondMap = reader
            .Read<TSecond>()
            .GroupBy(secondKey)
            .ToDictionary(g => g.Key, g => g.AsEnumerable());

        var thirdMap = reader
           .Read<TThird>()
           .GroupBy(thirdKey)
           .ToDictionary(g => g.Key, g => g.AsEnumerable());     

        foreach (var item in result)
        {
            IEnumerable<TSecond> second;
            if (secondMap.TryGetValue(firstKey(item), out second))
            {
                addSecond(item, second);
            }

            IEnumerable<TThird> third;
            if (thirdMap.TryGetValue(firstKey(item), out third))
            {
                addThird(item, third);
            }  
        }  
        return result.ToList();
    }
person armory09    schedule 02.09.2015