-
C# 表达式树实现匿名类型到列表返回模型的自动映射
前言:
在我们的业务中,展示列表时经常会联表查询,比如说我们有学生表和班级表,表结构如下:包含了学生表、班级表以及列表返回模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
/// <summary> /// 学生表 /// </summary> public class StudentInfo { /// <summary> /// 标识 /// </summary> public Guid Id { get ; set ; } /// <summary> /// 学号 /// </summary> public string Number { get ; set ; } /// <summary> /// 姓名 /// </summary> public string Name { get ; set ; } /// <summary> /// 班级标识 /// </summary> public Guid ClassId { get ; set ; } } /// <summary> /// 班级表 /// </summary> public class ClassInfo { /// <summary> /// 标识 /// </summary> public Guid Id { get ; set ; } /// <summary> /// 班级总人数 /// </summary> public int TotalNumber { get ; set ; } } /// <summary> /// 列表返回模型 /// </summary> public class ClassStudentModel { /// <summary> /// 学生标识 /// </summary> public Guid Id { get ; set ; } /// <summary> /// 学号 /// </summary> public string Number { get ; set ; } /// <summary> /// 学生名称 /// </summary> public string Name { get ; set ; } /// <summary> /// 班级总人数 /// </summary> public int TotalNumber { get ; set ; } } |
普通的查询语句,例子中的返回模型字段并不多,所以写4个字段也不费劲,但如果是十几二十个那就挺麻烦的了,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var query = from s in dbStore.Set<StudentInfo>() from c in dbStore.Set<ClassInfo>().Where(c => c.Id == s.ClassId).DefaultIfEmpty() select new { s, c }; // 一般一些业务中应该会有更多的查询条件,这里就省略了 // 比如: query = query.Where(e => e.s.Name == options.Name); var result = query.Select(e => new ClassStudentModel { Id = e.s.Id, Number = e.s.Number, Name = e.s.Name, TotalNumber = e.c.TotalNumber }).ToList(); |
所以我想有没有什么方法能够让这个匿名类型中的字段自动映射到列表的返回模型中呢?
正文:
使用表达式树+反射可以实现此需求,通过反射将各模型中的字段名与列表返回模型中的各字段进行对应,再利用表达式树进行拼接构造函数。有了这个思路之后呢,还有个问题,就是可能各模型中有很多相同的字段都可以和返回模型中的字段对应,比如说学生表里有Id,班级表中也有Id,那么到底是哪个Id和返回模型中的Id呢,为此,我又加了一个特性自动映射ParentAnonymousAttribute,通过此特性来判别取哪个模型中的Id,自动映射方法和特性代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/// <summary> /// 父级匿名特性 /// </summary> public class ParentAnonymousAttribute : Attribute { /// <summary> /// 构造函数 /// </summary> public ParentAnonymousAttribute( string parentName) { ParentName = parentName; } /// <summary> /// /// </summary> /// <param name="parentName"></param> /// <param name="name"></param> public ParentAnonymousAttribute( string parentName, string name) { ParentName = parentName; Name = name; } /// <summary> /// 父级匿名名称 /// </summary> public string ParentName { get ; set ; } /// <summary> /// 属性名称 /// </summary> public string Name { get ; set ; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
/// <summary> /// 自动select /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TGraph"></typeparam> /// <param name="query"></param> /// <param name="graph"></param> /// <returns></returns> public static IQueryable<TGraph> AutoSelect<T, TGraph>( this IQueryable<T> query, TGraph graph) { var defaultCtor = typeof (TGraph).GetConstructor(Type.EmptyTypes); if (defaultCtor == null ) { throw new Exception(); } var constructor = Expression.New(defaultCtor); var bindings = new List<MemberAssignment>(); var tExp = Expression.Parameter( typeof (T), "t" ); var typeT = typeof (T); var tProperties = typeT.GetProperties(); var graphProperties = typeof (TGraph).GetProperties().Where(e => e.SetMethod != null ).ToList(); var graphPointParentProps = graphProperties.Where(e => e.GetCustomAttribute<ParentAnonymousAttribute>() != null ).ToList(); var graphNoPointParentProps = graphProperties.Where(e => e.GetCustomAttribute<ParentAnonymousAttribute>() == null ).ToList(); foreach ( var item in graphPointParentProps) { var attr = item.GetCustomAttribute<ParentAnonymousAttribute>(); var pExp = Expression.Property(tExp, attr.ParentName); var realExp = Expression.Property(pExp, attr.Name ?? item.Name); bindings.Add(Expression.Bind(item, realExp)); } foreach ( var prop in tProperties) { var anoyClass = prop.PropertyType.GetProperties(); foreach ( var item in anoyClass) { if (graphNoPointParentProps.Any(a => a.Name == item.Name)) { var property = graphNoPointParentProps.Where(a => a.Name == item.Name).FirstOrDefault(); if (property.PropertyType != item.PropertyType) { continue ; } if (bindings.Any(e => e.Member.Name == property.Name)) { continue ; } var pExp = Expression.Property(tExp, prop.Name); var realExp = Expression.Property(pExp, item.Name); bindings.Add(Expression.Bind(property, realExp)); } } } var init = Expression.MemberInit(constructor, bindings); var final = Expression.Lambda<Func<T, TGraph>>(init, tExp); return query.Select(final); } |
先给列表返回模型的字段加上特性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/// <summary> /// 列表返回模型 /// </summary> public class ClassStudentModel { /// <summary> /// 学生标识 /// </summary> [ParentAnonymous( "s" )] public Guid Id { get ; set ; } /// <summary> /// 学号 /// </summary> public string Number { get ; set ; } /// <summary> /// 学生名称 /// </summary> public string Name { get ; set ; } /// <summary> /// 班级总人数 /// </summary> public int TotalNumber { get ; set ; } } |
然后再改一下查询方法:
1
2
3
4
5
|
var query = from s in dbStore.Set<StudentInfo>() from c in dbStore.Set<ClassInfo>().Where(c => c.Id == s.ClassId).DefaultIfEmpty() select new { s, c }; var result = query.AutoSelect( new ClassStudentModel()).ToList(); |
至此,自动映射,大功告成
出处:https://www.cnblogs.com/ttyycc/p/17202549.html
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式