我正在使用Linq查詢MS CRM 2011 Web服務。我有一個查詢導致非常差的SQL,它會獲取太多的中間數據,並且它的性能很糟糕!我是新來的,所以它很可能是我使用它的方式......使用N-N連接以PredicateBuilder優化Linq查詢
我有通過N-N關係鏈接兩個實體:Product
和SalesLink
。我想從他們的SerialNumber
以及與之相關的所有SalesLink
中恢復一堆Product
。
這是我使用PredicateBuilder查詢:
// Build inner OR predicate on Serial Number list
var innerPredicate = PredicateBuilder.False<Xrm.c_product>();
foreach (string sn in serialNumbers) {
string temp = sn; // This temp assignement is important!
innerPredicate = innerPredicate.Or(p => p.c_SerialNumber == temp);
}
// Combine predicate with outer AND predicate
var predicate = PredicateBuilder.True<Xrm.c_product>();
predicate = predicate.And(innerPredicate);
predicate = predicate.And(p => p.statecode == (int)CrmStateValueType.Active);
// Inner Join Query
var prodAndLinks = from p in orgContext.CreateQuery<Xrm.c_product>().AsExpandable()
.Where(predicate)
.AsEnumerable()
join link in orgContext.CreateQuery<Xrm.c_saleslink>()
on p.Id equals link.c_ProductSalesLinkId.Id
where link.statecode == (int)CrmStateValueType.Active
select new {
productId = p.Id
, productSerialNumber = p.c_SerialNumber
, accountId = link.c_Account.Id
, accountName = link.c_Account.Name
};
...
使用SQL事件探查器,我看到了,它會導致一個沒有WHERE子句的中間SQL查詢,看起來像這樣:
select
top 5001 "c_saleslink0".statecode as "statecode"
...
, "c_saleslink0".ModifiedOnBehalfByName as "modifiedonbehalfbyname"
, "c_saleslink0".ModifiedOnBehalfByYomiName as "modifiedonbehalfbyyominame"
from
c_saleslink as "c_saleslink0" order by
"c_saleslink0".c_saleslinkId asc
這會返回大量的(無用的)數據。我認爲加入是在客戶端而不是在數據庫端完成的...
我應該如何改進此查詢?我跑了大約3分鐘,這是完全不能接受的。
謝謝。
「解決方案」
基於Daryl的答案使用QueryExpression,而不是LINQ到CRM,我得到這個它得到完全相同的結果。
var qe = new QueryExpression("c_product");
qe.ColumnSet = new ColumnSet("c_serialnumber");
var filter = qe.Criteria.AddFilter(LogicalOperator.Or);
filter.AddCondition("c_serialnumber", ConditionOperator.In, serialNumbers.ToArray());
var link = qe.AddLink("c_saleslink", "c_productid", "c_productsaleslinkid");
link.LinkCriteria.AddCondition("statecode", ConditionOperator.Equal, (int)CrmStateValueType.Active);
link.Columns.AddColumns("c_account");
var entities = serviceProxy.RetrieveMultiple(qe).Entities.ToList();;
var prodAndLinks = entities.Select(x => x.ToEntity<Xrm.c_product>()).Select(x =>
new {
productId = x.c_productId
, productSerialNumber = x.c_SerialNumber
, accountId = ((Microsoft.Xrm.Sdk.EntityReference)((Microsoft.Xrm.Sdk.AliasedValue)x["c_saleslink1.c_account"]).Value).Id
, accountName = ((Microsoft.Xrm.Sdk.EntityReference)((Microsoft.Xrm.Sdk.AliasedValue)x["c_saleslink1.c_account"]).Value).Name
}).ToList();
我真的也喜歡找使用LINQ的解決方案,但它似乎LINQ到CRM只是現在還沒有...
我沒有用PredicateBuilder成功的CRM,但你可能想看看我的答案(使用動態Linq)和接受的答案(使用PredicateBuilder)的問題[如何獲得今天的所有生日?](http://stackoverflow.com/questions/10142724/how-to-get-all-the-birthdays今天/ 10146065#10146065)成功實現你正在嘗試做的事情。 –
我的回答是否回答你的問題? – Daryl
@Daryl:是的,這樣做,謝謝。我本來喜歡Linq to CRM解決方案,但除了在兩個較小的查詢中分解我的查詢外,我沒有成功...... LINQ到CRM似乎並不支持'WHERE IN'。 – dstj