Multi-Mapper 在 Dapper 中的一对多关系
Multi-Mapper in Dapper one to many relations
我正在尝试通过一对多关系获取我的数据库的值
我有这样的 object
学生
[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();
按照说明Here我所要做的就是扩展 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
以获取 enrollment => ctr = enrollment.StudentId
中 CourseId
的值。
好的,现在我面临另一个问题,如何获取 courses
的值
这是我的代码
((student, courses) => courses.ToList().ForEach(s=> student.Enrollments.ToList().ForEach(x=>x.Course = new Course
{
Title = s.Title
}))
我只得到最后一个值
这是我解决问题的方法
如上 UPDATE 2 的详细信息,我添加了一个变量 ctr
以从 Enrollment
获取 CourseId
的值并传递给 Course
得到正确的值。之后我面临另一个问题如何从 Student.Enrollment.Course
传递 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 级层次结构 here
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();
}
我正在尝试通过一对多关系获取我的数据库的值 我有这样的 object
学生
[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();
按照说明Here我所要做的就是扩展 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
以获取 enrollment => ctr = enrollment.StudentId
中 CourseId
的值。
好的,现在我面临另一个问题,如何获取 courses
的值
这是我的代码
((student, courses) => courses.ToList().ForEach(s=> student.Enrollments.ToList().ForEach(x=>x.Course = new Course { Title = s.Title }))
我只得到最后一个值
这是我解决问题的方法
如上 UPDATE 2 的详细信息,我添加了一个变量 ctr
以从 Enrollment
获取 CourseId
的值并传递给 Course
得到正确的值。之后我面临另一个问题如何从 Student.Enrollment.Course
传递 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 级层次结构 here
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();
}