文章目录
- 前言
- 一、匿名类的自动映射
- 1.定义模型表
- 2.非自动映射查询
- 3.自动映射查询
- 3.1 ParentAnonymousAttribute特性类
- 3.2 AutoSelect扩展函数封装
- 3.3 改造ClassStudentModel映射模型类
- 3.4 使用
前言
.net匿名类是一种临时创建的类,可以在运行时动态地创建。它可以用于简化代码,避免创建不必要的类。在使用匿名类时,编译器会自动为其创建一个对应的类,并将属性自动映射到该类中。这样可以方便地进行数据传递和处理,通常用于临时存储数据或传递参数。在 .NET 中,可以使用匿名类来创建一个具有一组属性的对象,这些属性可以在创建时进行初始化。例如,可以使用匿名类来创建一个包含姓名和年龄属性的对象,如下所示:
代码语言:javascript复制var person = new { Name = "John", Age = 30 };
在这个例子中,我们创建了一个名为 person 的匿名类对象,该对象具有 Name 和 Age 两个属性,并分别初始化为 “John” 和 30。
一、匿名类的自动映射
在我们业务中经常需要使用到匿名类型,特别是数据库连表查询。因为根据业务变动需要返回字段信息不同,甚至有计算数据。因为是匿名类,在匿名类再次参加链表是关联不出属性的,这就需要进一步处理匿名类数据。
以下是匿名类的自动映射解决方案
1.定义模型表
1、StudentInfo
代码语言:javascript复制///
/// 学生表
///
public class StudentInfo
{
///
/// 标识
///
public Guid Id { get; set; }
///
/// 学号
///
public string Number { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 班级标识
///
public Guid ClassId { get; set; }
}
2、ClassInfo
代码语言:javascript复制///
/// 班级表
///
public class ClassInfo
{
///
/// 标识
///
public Guid Id { get; set; }
///
/// 班级总人数
///
public int TotalNumber { get; set; }
}
3、ClassStudentModel
代码语言:javascript复制///
/// 列表返回模型
///
public class ClassStudentModel
{
///
/// 学生标识
///
public Guid Id { get; set; }
///
/// 学号
///
public string Number { get; set; }
///
/// 学生名称
///
public string Name { get; set; }
///
/// 班级总人数
///
public int TotalNumber { get; set; }
}
2.非自动映射查询
对于数据库表中少量字段可以进行如下写法返回数据
代码语言:javascript复制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();
3.自动映射查询
使用表达式树 反射可以实现此需求,通过反射将各模型中的字段名与列表返回模型中的各字段进行对应,再利用表达式树进行拼接构造函数。
对于两个类有相同字段可以进行如下处理:比如说学生表里有Id,班级表中也有Id,可以加了一个特性自动映射ParentAnonymousAttribute,通过此特性来判别取哪个模型中的Id,具体代码如下:
3.1 ParentAnonymousAttribute特性类
代码语言:javascript复制///
/// 父级匿名特性
///
public class ParentAnonymousAttribute : Attribute
{
///
/// 构造函数
///
public ParentAnonymousAttribute(string parentName)
{
ParentName = parentName;
}
///
///
///
///
///
public ParentAnonymousAttribute(string parentName, string name)
{
ParentName = parentName;
Name = name;
}
///
/// 父级匿名名称
///
public string ParentName { get; set; }
///
/// 属性名称
///
public string Name { get; set; }
}
3.2 AutoSelect扩展函数封装
代码语言:javascript复制///
/// 自动select
///
///
///
///
///
///
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);
}
3.3 改造ClassStudentModel映射模型类
代码语言:javascript复制///
/// 列表返回模型
///
public class ClassStudentModel
{
///
/// 学生标识
///
[ParentAnonymous("s")]
public Guid Id { get; set; }
///
/// 学号
///
public string Number { get; set; }
///
/// 学生名称
///
public string Name { get; set; }
///
/// 班级总人数
///
public int TotalNumber { get; set; }
}
3.4 使用
代码语言:javascript复制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();