使用 ExpressionMove 对表达式参数进行替换

一,为什么表达式的参数需要替换?
    在使用领域模型编程时,我们的领域模型经常和数据模型是不一样的。领域模型最为贴近业务,数据模型反应的是数据库表。这二者的不一致经常给我们带来代码的复杂化。在模型的转换上,我们有 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 List Query(QueryModel queryModel)
        {
            Expressionbool>> 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;
    Expressionbool>> 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);
    });

    Expressionbool>> 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);
    });


    Expressionbool>> 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 了。

你可能感兴趣的:(使用 ExpressionMove 对表达式参数进行替换)