Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.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
Entity framework 通过OrderByDescending和SaveChanges使用Linq到实体_Entity Framework_C# 4.0_Linq To Entities - Fatal编程技术网

Entity framework 通过OrderByDescending和SaveChanges使用Linq到实体

Entity framework 通过OrderByDescending和SaveChanges使用Linq到实体,entity-framework,c#-4.0,linq-to-entities,Entity Framework,C# 4.0,Linq To Entities,我看到Linq对实体的行为与我对Linq工作原理的理解不一致。请考虑以下片段: MWGRCEntities entities = new MWGRCEntities(); foreach (EDMXModel.Classes.RiskScoreMetric rsm in entities.RiskScoreMetrics.Where(rsmq.StatusCode != (int)KnownCodes.RiskScoreMetricStatusInActive)) { //Magic

我看到Linq对实体的行为与我对Linq工作原理的理解不一致。请考虑以下片段:

MWGRCEntities entities = new MWGRCEntities();

foreach (EDMXModel.Classes.RiskScoreMetric rsm in entities.RiskScoreMetrics.Where(rsmq.StatusCode != (int)KnownCodes.RiskScoreMetricStatusInActive))
{
    //Magic happens here...
    rsm.ImpactOverall = (rsm.ImpactWorkingGroup + rsm.ImpactExecutive) / 2;
    rsm.LikelihoodOverall = (rsm.LikelihoodWorkingGroup + rsm.LikelihoodExecutive) / 2;
}

int rank = 0;
double prevScore = -1;
double score = -2;
foreach (EDMXModel.Classes.RiskScoreMetric rsm in entities.RiskScoreMetrics.Where(rsmq.StatusCode != (int)KnownCodes.RiskScoreMetricStatusInActive).OrderByDescending(rsmq => Math.Round((Math.Round(rsmq.ImpactOverall, 3) + Math.Round(rsmq.LikelihoodOverall, 3)), 3)))
{
    score = Math.Round((Math.Round(rsm.ImpactOverall, 3) + Math.Round(rsm.LikelihoodOverall, 3)), 3);

    if (score != prevScore)
        rank++;

    rsm.Ranking = rank;
    prevScore = score;
}

entities.SaveChanges();
我预计RiskScoreMetric对象将在第二个foreach循环中使用在第一个foreach循环中设置的ImpactTotal和LikelihoodTotal值进行排序。然而,Linq似乎在第二个foreach循环中根据原始的ImpactTotal和LikelihoodTotal值(如中所示,数据库中的值不是内存中的值)进行排序。我只需在第二个foreach循环之前添加对entities.SaveChanges()的第二个调用,就可以轻松修复代码

有人能告诉我这种行为是否是预期的吗?如果是,为什么


谢谢大家!

您需要记住,这里使用的
OrderbyDescending
IQueryable
的扩展方法,而不是
IEnumerable
。此扩展方法和用作此方法参数的LINQ表达式-
rsmq=>Math.Round(…)
-不会在内存中的数据结构/集合上执行,但它仅表示表达式树。表达式树的实际情况取决于数据提供程序(在类型为
IQueryable
的queryable对象内部引用)。在Entity Framework/LINQ to Entities的情况下,此提供程序将表达式树转换为SQL字符串(方言取决于该提供程序的详细信息,例如SQL Server的T-SQL、Oracle或MySQL的其他原生SQL方言等)

转换后的SQL将被发送到数据库服务器,并将在数据库引擎中执行,而数据库引擎不知道您对内存中已加载的实体所做的任何更改

所有LINQ to Entities查询始终基于表中的当前状态和数据值在数据库中执行。他们从不考虑你是否已经加载了实体,他们有哪些价值,不管是否改变。(
DbSet.Find
ObjectSet.GetObjectByKey
是检查具有提供键的实体是否已加载到内存中的唯一例外,但这些方法不是LINQ to Entities查询,尽管如果它们无法找到实体,它们将发出LINQ to Entities查询,即
SingleOrDefault
附加到上下文。)

作为旁注:需要将表达式树转换为SQL也是不能在LINQ to Entities查询中使用任意.NET方法的原因,因为在大多数情况下,不可能转换为SQL,或者LINQ to Entities提供程序不知道如何转换它。类似于

rsmq => MySpecialRoundMethod(...)

…其中,
MySpecialRoundMethod
是您用C编写的自定义方法,将使用LINQ to对象(在
IEnumerable
上),但不使用LINQ to实体(在
IQueryable
上)。碰巧对于
Math.Round(…)
实现了到SQL的转换,这样您就可以将其与实体框架一起使用了。

Awesome response。非常感谢你。我注意到有些方法不能用在这些表达式中,不知道为什么。我现在更明白发生了什么。这是否意味着,如果我将一个对象插入到上下文中,然后尝试使用select linq查询查找它,我将找不到它,因为它尚未插入到数据库中?@AEberhard:是的,没错。您看到的异常可能是臭名昭著的“无法转换为存储表达式”异常,这是最常被问到的问题之一。我相信人们对这一点感到困惑的是术语“存储表达式”,在99%的情况下,它只表示“SQL”。我认为他们使用的是更抽象的术语,因为EF不需要翻译成SQL。如果有一家公司有一个特殊的数据库系统和一种叫做“Babble”的专有查询语言,他们可以为Babble编写一个LINQ to Entities提供者。“商店用语”应该是“胡言乱语”。