一,为什么表达式的参数需要替换?
在使用领域模型编程时,我们的领域模型经常和数据模型是不一样的。领域模型最为贴近业务,数据模型反应的是数据库表。这二者的不一致经常给我们带来代码的复杂化。在模型的转换上,我们有 AutoMapper 这样的工具进行转换。 在查询时,领域模型的查询表达式是不能直接给数据模型进行查询的,我也没有找到有谁造过这样的轮子。
比如,我们现在有领域模型 Model1 代码如下:
public class Model1 { public int Id { get; set; } public string Name { get; set; } public DateTime CreateTime { get; set; } public string[] Values { get; set; }//["a", "b", "c"] public int[] IntValues { get; set; }//[1, 2, 3] }
有数据模型 Model4 代码如下:
public class Model4 { public int id { get; set; } public string Name { get; set; } public string values { get; set; }//",a,b,c," public string intvalues { get; set; }//",1,2,3," }
然后在数据模型所在项目(一般是基础设施层)进行表达式或SQL语句的拼接。
public ListQuery(QueryModel queryModel) { Expression bool>> expression = null; if (queryModel.Id > 0) expression = x => x.id == queryModel.Id; if (!string.IsNullOrEmpty(queryModel.Key)) expression = expression.And(x => x.Name.Contains(queryModel.Key)); return Where(expression); }
然而,这样的坏处也是显而易见的,增加了复杂度,而且在添加一个查询字段、或一个字段的查询方式时,都需要对查询模型进行修改。比如上边的例子中如果想增加个按 [不等于某个Id] 进行查询的需求,那 QueryModel 要增加字段, 查询方法里需要再拼接一段。
这时如果能有一个工具对表达式进行转换的话,那就方便太多了。然后 ExpressionMove 就诞生了。
二,ExpressionMove 使用方法。
项目地址 : https://github.com/zl33842901/ExpressionMove
Nuget 关键字: xLiAd.ExpressionMove
具体使用方法可参见项目里的 UnitTest,在两个模型完全一样时(或者说用于查询的字段完全一样时),只需要用你的表达式 .BuildMover().MoveTo
public class Model2 { public int Id { get; set; } public string Name { get; set; } public DateTime CreateTime { get; set; } } Expressionbool>> expression = x => x.Id == 5 && x.Name == "a" && x.CreateTime < DateTime.Now; Expression bool>> result = expression.BuildMover().MoveTo ();
当模型的一些字段类型一样,名称不一样时,可以使用配置类进行配置,然后在使用时进行转换。
public class Model3 { public int id { get; set; } public string MyName { get; set; } public DateTime CreateTime { get; set; } } private MoverTypeConfiguration Configuration { get; } = new MoverTypeConfiguration(x => { x.CreateMap() .FieldMap(x => x.Id, x => x.id) .FieldMap(x => x.Name, x => x.MyName); }); Expression bool>> expression = x => x.Id == 5 && x.Name == "a" && x.CreateTime < DateTime.Now; var provider = Configuration.Build(); var result = provider.Load(expression).MoveTo ();
这种情况也可以使用字段的名称特性标记来实现。
当领域模型是数组,数据模型是逗号分隔的字符串时(SQLServer里常用,PG里不必了),ExpressionMove 现在只支持 Contains 方法。
private MoverTypeConfiguration Configuration { get; } = new MoverTypeConfiguration(x => { x.CreateMap() .FieldMap(x => x.Id, x => x.id) .FieldMap(x => x.IntValues, x => x.intvalues) .FieldMap(x => x.Values, x => x.values); }); Expression bool>> expression = x => x.Id == 5 && x.IntValues.Contains(6) && x.Values.Contains("b"); var provider = Configuration.Build(); var result = provider.Load(expression).MoveTo ();
当然这种实现并不是很完善,在需要存取数组的场景下,推荐使用 PG(PostgreSql),我的另一个组件 xLiAd.DapperEx 有专门为PG写的仓储,可以支持数组字段的操作。
这样基本能覆盖90%以上的场景了,再也不用写 QueryModel 了。