Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.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
C# 我可以在实体框架中使用带有动态datePartArg的SqlFunctions.DateDiff()吗?_C#_Entity Framework_Exception_Dynamic_Datediff - Fatal编程技术网

C# 我可以在实体框架中使用带有动态datePartArg的SqlFunctions.DateDiff()吗?

C# 我可以在实体框架中使用带有动态datePartArg的SqlFunctions.DateDiff()吗?,c#,entity-framework,exception,dynamic,datediff,C#,Entity Framework,Exception,Dynamic,Datediff,由于注释行,以下代码引发EntityCommandCompilationException: var datePartArg = "dd"; var minutesInStatePerSegment = await db.History_WorkPlaceStates .Where(x => selector.StartTimeUtc <= x.Started && x.Ended < selector.EndTimeUtc) .

由于注释行,以下代码引发
EntityCommandCompilationException

var datePartArg = "dd";
var minutesInStatePerSegment = await db.History_WorkPlaceStates
        .Where(x => selector.StartTimeUtc <= x.Started && x.Ended < selector.EndTimeUtc)
        .Select(x => new {
                    start = x.Started,
                    minutes = x.Minutes,
                    state = x.State,
                })
        .GroupBy(x => new {
                    //This causes an exception:
                    segment = SqlFunctions.DateDiff(datePartArg, selector.StartTimeUtc, x.start),
                    state = x.state,
                })
        .Select(x => new {
                    state = x.Key.state,
                    segment = x.Key.segment,
                    minutes = x.Sum(y => y.minutes),
                }).ToListAsync();
var datePartArg=“dd”;
var minutesInStatePerSegment=等待db.History_WorkPlaceStates
.Where(x=>selector.StartTimeUtc新{
开始=x.开始,
分钟=x.分钟,
state=x.state,
})
.GroupBy(x=>new{
//这会导致一个异常:
段=SqlFunctions.DateDiff(datePartArg,selector.starttimetc,x.start),
state=x.state,
})
.选择(x=>new{
state=x.Key.state,
段=x.Key.segment,
分钟=x.Sum(y=>y.minutes),
}).ToListAsync();
这是因为SQL Server中的
DateDiff
只能将文字字符串用作其第一个参数,而不能使用变量。实体框架在SQL中生成一个变量,因此我们得到了异常


有没有办法解决这个问题?

您可以创建以下扩展方法来解决这个问题。使用DateDiff时,只需使用此扩展方法替换GroupBy函数:

    private static object GetMemberValue(MemberExpression member) {
        var objectMember = Expression.Convert(member, typeof(object));
        var getterLambda = Expression.Lambda<Func<object>>(objectMember);
        var getter = getterLambda.Compile();
        return getter();
    }

    public static IQueryable<IGrouping<TKey, TSource>> GroupByDateDiff<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector) {
        var body = (NewExpression)keySelector.Body;
        foreach (var arg in body.Arguments) {
            if (arg.NodeType == ExpressionType.Call) {
                var callNode = (MethodCallExpression)arg;
                if (callNode.Method.Name == "DateDiff") {
                    var dateDiffFirstArg = callNode.Arguments[0];
                    if (dateDiffFirstArg.NodeType == ExpressionType.Constant) {
                        //It was already a constant, so we're good.
                    }
                    else {
                        //HACK: This will break if the internal implementation of ReadOnlyCollection changes.
                        var listInfo = typeof(ReadOnlyCollection<Expression>).GetField("list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                        var list = (IList)listInfo.GetValue(callNode.Arguments);
                        if (dateDiffFirstArg.NodeType == ExpressionType.MemberAccess) {
                            list[0] = Expression.Constant((string)GetMemberValue((MemberExpression)dateDiffFirstArg));
                        }
                        else {
                            throw new ArgumentException($"{nameof(GroupByDateDiff)} was unable to parse the datePartArg argument to the DateDiff function.");
                        }
                    }
                }
            }
        }
        return source.GroupBy(keySelector);
    }
私有静态对象GetMemberValue(MemberExpression成员){
var objectMember=Expression.Convert(成员,typeof(对象));
var getterLambda=Expression.Lambda(objectMember);
var getter=getterLambda.Compile();
返回getter();
}
公共静态IQueryable GroupByDateDiff(此IQueryable源、表达式键选择器){
var body=(NewExpression)keySelector.body;
foreach(body.Arguments中的变量arg){
if(arg.NodeType==ExpressionType.Call){
var callNode=(MethodCallExpression)arg;
if(callNode.Method.Name==“DateDiff”){
var dateDiffFirstArg=callNode.Arguments[0];
if(dateDiffFirstArg.NodeType==ExpressionType.Constant){
//这已经是一个常数了,所以我们很好。
}
否则{
//HACK:如果ReadOnlyCollection的内部实现发生更改,这将中断。
var listInfo=typeof(ReadOnlyCollection).GetField(“list”,System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var list=(IList)listInfo.GetValue(callNode.Arguments);
if(dateDiffFirstArg.NodeType==ExpressionType.MemberAccess){
列表[0]=表达式.常量((字符串)GetMemberValue((MemberExpression)dateDiffFirstArg));
}
否则{
抛出新ArgumentException($“{nameof(GroupByDateDiff)}无法将datePartArg参数解析为DateDiff函数。”);
}
}
}
}
}
返回source.GroupBy(keySelector);
}
请注意,这使用反射来访问私有变量,如果ReadOnlyCollection的实现发生更改,则可能会中断。但是,如果发生这种情况,解决这个问题将相当容易