Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Guid书签的C#表达式_C#_Linq_Linq Expressions - Fatal编程技术网

使用Guid书签的C#表达式

使用Guid书签的C#表达式,c#,linq,linq-expressions,C#,Linq,Linq Expressions,我需要处理几个需要同步/备份的表。所有这些表的类都实现了ITrackModifiedDate: interface ITrackModifiedDate { DateTime ModifiedDate { get; set; } } 我需要分批完成这些任务,这意味着我需要把我上一次到达的地方添加书签。因此,我可以按ModifiedDate排序,只需跟踪上一次ModifiedDate。但计划中有一个漏洞:多个记录具有相同的ModifiedDate,这很容易发生。这意味着我需要一个二级标识

我需要处理几个需要同步/备份的表。所有这些表的类都实现了
ITrackModifiedDate

interface ITrackModifiedDate
{
    DateTime ModifiedDate { get; set; }
}
我需要分批完成这些任务,这意味着我需要把我上一次到达的地方添加书签。因此,我可以按
ModifiedDate
排序,只需跟踪上一次
ModifiedDate
。但计划中有一个漏洞:多个记录具有相同的
ModifiedDate
,这很容易发生。这意味着我需要一个二级标识符,通常我唯一能依赖的就是key字段,它总是一个
Guid

我在
表达式中得到了一些帮助,但是当我尝试修补添加“大于”子句时,事情就坏了

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();
}
异步任务GetModifiedRecords(DateTime modifiedSince,Guid lastId),其中T:class,ITrackModifiedDate
{
var parameterExp=表达式参数(typeof(T),“x”);
var propertyExp=Expression.Property(parameterExp,keyField);
var target=表达式常数(lastId);
var greaterThanMethod=Expression.GreaterThan(propertyExp,target);
var lambda=Expression.lambda(greaterThanMethod,parameterExp);
var query=db.Set()
.其中(t=>t.ModifiedDate>modifiedSince||
t、 ModifiedDate==modifiedSince&&lambda.Invoke(t));
var orderByExp=Expression.Lambda(propertyExp,parameterExp);
var thenByMethodGeneric=typeof(可查询)
.GetMethods()
.Single(mi=>mi.Name==“ThenBy”&&mi.GetParameters().Length==2);
var thenByMethod=thenByMethodGeneric.MakeGenericMethod(typeof(T),propertyExp.Type);
//先按日期订购,然后按id订购
query=query.OrderBy(t=>t.ModifiedDate)
.AsQueryable();
query=(IQueryable)thenByMethod.Invoke(null,新对象[]{query,orderByExp});
return wait query.ToListAsync();
}
尝试运行此查询将导致:

System.InvalidOperationException:没有为类型“System.Guid”和“System.Guid”定义大于的二进制运算符

哦,天哪。看起来像人类一样,吉德人不喜欢互相比较。要么这样,要么我使用了错误的比较表达式

我想到的一个显而易见的解决方案是将Guid转换为字符串以进行比较,但是(a)这似乎有点低效,(b)我不知道如何编写将Guid转换为字符串的
表达式


转换为字符串是正确的方法吗?如果是这样,什么
表达式
可以完成此工作?如果没有,正确的方法是什么?

一般的方法是用调用替换不受支持的
Guid
运算符,例如代替

guidA > guidB
使用

在您的情况下,替换

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

这适用于大多数查询提供程序(LINQ到对象、LINQ到实体(EF6))。不幸的是,EF Core 2.x不适用于需要。如果是这种情况,请按照链接答案中的说明注册自定义
GuidFunctions
类,并改用此类:

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

不太可能将Guid转换为字符串——使用
Expression.call调用它的ToString方法很容易——但将表达式转换为SQL的东西(可能是EF)知道该怎么办。@canton7我刚才想到的另一个关于字符串排序的问题是,它可能与我的数据库(Postgres,FWIW)处理order by子句的方式不一致。我有一种感觉,db排序不是字符串式的。-检查这些链接,我正在使用EF Core 2.x:-)很好,我喜欢你的
GuidFunctions
类,但是你如何将其应用于一般情况?i、 e.如何生成调用扩展方法的
表达式
?@ShaulBehr Lol,真倒霉:)让我更新答案。
var compareTo = Expression.Call(propertyExp, "CompareTo", Type.EmptyTypes, target);
var greaterThanMethod = Expression.GreaterThan(compareTo, Expression.Constant(0));
var greaterThanMethod = Expression.Call(
    typeof(GuidFunctions), "IsGreaterThan", Type.EmptyTypes,
    propertyExp, target);