C#表达式以使用Guid书签 [英] C# Expression to use Guid bookmark

查看:67
本文介绍了C#表达式以使用Guid书签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要处理几个需要同步/备份的表的要求.所有这些表的类都实现ITrackModifiedDate:

I have a requirement to work through several tables that need to be synchronized/backed up. All of these tables' classes implement ITrackModifiedDate:

interface ITrackModifiedDate
{
    DateTime ModifiedDate { get; set; }
}

我需要分批处理这些内容,这意味着我需要为上次到达的位置添加书签.因此,我可以按ModifiedDate进行排序,并仅跟踪我的上一个ModifiedDate.但是计划中有一个折痕:很容易发生多个记录具有相同的ModifiedDate的情况.这意味着我需要一个辅助标识符,而我通常可以唯一依赖的是键字段,该字段始终是Guid.

I need to work through these in batches, which means I need to bookmark where I last got up to. So I can sort by ModifiedDate, and just keep track of my last ModifiedDate. But there's a wrinkle in the plan: it can easily happen that multiple records have the identical ModifiedDate. That means I need a secondary identifier, and the only thing I can generically rely on being there is the key field, which is invariably a Guid.

此处中,我在Expression方面获得了一些帮助,但是当我尝试修补添加大于"子句,事情就坏了.

I got some help in the Expression stuff from here, but when I tried tinkering to add in the "greater than" clause, things broke.

async Task<ICollection<T>> GetModifiedRecords<T>(DateTime modifiedSince, Guid lastId) where T : class, ITrackModifiedDate
{
    var parameterExp = Expression.Parameter(typeof(T), "x");
    var propertyExp = Expression.Property(parameterExp, keyField);
    var target = Expression.Constant(lastId);
    var greaterThanMethod = Expression.GreaterThan(propertyExp, target);
    var lambda = Expression.Lambda<Func<T, bool>>(greaterThanMethod, parameterExp);

    var query = db.Set<T>()
                  .Where(t => t.ModifiedDate > modifiedSince ||
                              t.ModifiedDate == modifiedSince && lambda.Invoke(t));

    var orderByExp = Expression.Lambda(propertyExp, parameterExp);
    var thenByMethodGeneric = typeof(Queryable)
                               .GetMethods()
                               .Single(mi => mi.Name == "ThenBy" && mi.GetParameters().Length == 2);

    var thenByMethod = thenByMethodGeneric.MakeGenericMethod(typeof(T), propertyExp.Type);
    // first order by date, then id
    query = query.OrderBy(t => t.ModifiedDate)
                 .AsQueryable();
    query = (IQueryable<T>)thenByMethod.Invoke(null, new object[] { query, orderByExp });
    return await query.ToListAsync();
}

尝试运行此查询会导致:

Attempting to run this query results in:

System.InvalidOperationException:未为类型'System.Guid'和'System.Guid'定义二进制运算符GreaterThan.

System.InvalidOperationException: The binary operator GreaterThan is not defined for the types 'System.Guid' and 'System.Guid'.

哦,亲爱的.吉德斯像人类一样,不喜欢互相比较.要么是,否则我使用了错误的比较表达式.

Oh dear. It seems Guids, like humans, don't like being compared with each other. Either that, or I'm using the wrong comparison expression.

一个显而易见的解决方案是将Guid转换为字符串以进行比较,但是(a)似乎效率不高,并且(b)我不知道如何编写将转换的Expression字符串的Guid.

The obvious solution that jumps to mind is to convert the Guid to a string for comparison purposes, but (a) that seems a little inefficient, and (b) I don't know how to write an Expression that converts a Guid to a string.

转换为字符串是否正确?如果是这样,Expression将做什么工作?如果没有,正确的方法是什么?

Is converting to a string the right way to go? If so, what Expression will do the job? If not, what's the correct approach?

推荐答案

一般方法是将不支持的Guid运算符替换为

The general approach is to replace the unsupported Guid operators with Guid.CompareTo(Guid) calls, e.g. instead of

guidA > guidB

使用

guidA.CompareTo(guidB) > 0

根据您的情况,替换

 var greaterThanMethod = Expression.GreaterThan(propertyExp, target);

使用

var compareTo = Expression.Call(propertyExp, "CompareTo", Type.EmptyTypes, target);
var greaterThanMethod = Expression.GreaterThan(compareTo, Expression.Constant(0));

这适用于大多数查询提供程序(LINQ到对象,LINQ到实体(EF6)).不幸的是,它不适用于需要

This works for most of the query providers (LINQ to Objects, LINQ To Entities (EF6)). Unfortunately doesn't work with EF Core 2.x which requires a different approach. If that's the case, register the custom GuidFunctions class as explained in the linked answer, and use this instead:

var greaterThanMethod = Expression.Call(
    typeof(GuidFunctions), "IsGreaterThan", Type.EmptyTypes,
    propertyExp, target);

这篇关于C#表达式以使用Guid书签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆