例えば
もし、以下のようなメンバークラスがあったとして
(説明のためにしょっぱくなっていますがご勘弁ください!!)
public class Member
{
public int Id { get; set; }
public string Name { get; set; }
public string ClassCode { get; set; }
public string ClassName { get; set; }
public string GradeCode { get; set; }
public string GradeName { get; set; }
}
それを以下のようなListプロパティを持つ学年、組、生徒に一発でマッピングさせたい場合、この記事はお役に立てると思います。
public class Grade
{
public string GradeCode { get; set; }
public string GradeName { get; set; }
public List<Class> Classes { get; set; }
}
public class Class
{
public string ClassCode { get; set; }
public string ClassName { get; set; }
public List<Student> Students { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
やり方
まずは完成形をご覧ください。
var grades = new List<Grade>(); // 最終的にこのListにマッピングします
using (var db = new MyDbContext())
{
db.Database.Connection.Query<Student, Class, Grade, Student>(
"select * from members",
(s, c, g) =>
{
if (!grades.Contains(g))
{
c.Students = new List<Student>() { s };
g.Classes = new List<Class>() { c };
grades.Add(g);
return s;
}
Grade grade = grades.Single(gl => gl.Equals(g));
if (!grade.Classes.Contains(c))
{
c.Students = new List<Student>() { s };
grade.Classes.Add(c);
return s;
}
Class clazz = grade.Classes.Single(cl => cl.Equals(c));
clazz.Students.Add(s);
return s;
},
splitOn: "ClassCode,GradeCode");
}
- ポイント
- Dapperの戻り値でマップさせられないので、内部のFuncでコネコネして作成する
- Func内のreturnはダミーで意味はありません
- Equalメソッドをoverrideして等価判定を簡潔に表現する(本題とは直接は関係ないですが)
ポイント3のサンプルは以下の通りです。
public class Grade
{
public string GradeCode { get; set; }
public string GradeName { get; set; }
public List<Class> Classes { get; set; }
// コードと名称の値が一致したら等価と判定する
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
Grade g = (Grade)obj;
return (GradeCode == g.GradeCode) && (GradeName == g.GradeName);
}
// Equalsをoverrideすると併せて書かないと警告がでます
// 同じくコードと名称のみハッシュ対象とします
public override int GetHashCode()
{
var hashCode = 780226712;
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(GradeCode);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(GradeName);
return hashCode;
}
}
具体例
- Memberデータ
- 結果
foreach (var grade in grades)
{
Console.WriteLine("------------");
Console.WriteLine(grade.GradeName);
var classes = grade.Classes.Select(c => c);
foreach (var clazz in classes)
{
Console.WriteLine("--------");
Console.WriteLine(clazz.ClassName);
var students = clazz.Students.Select(s => s);
foreach (var student in students)
{
Console.WriteLine(student.Name);
}
}
}
意図した通りにマッピングさせられました。
参考サイト
How do I map lists of nested objects with Dapper
本ソースをgithubに公開しております。(しょっぱいです。)
githubサンプルソース