如何组合多部分 LINQ to Entities 查询
我在 Stack Exchange 的代码审查(测试版)上发布了此代码片段,以获得有关如何最好地重构多部分的一些反馈< code>LINQ 查询。
由于对 LINQ
比较陌生,我不太确定从哪里开始这个查询。
如果有人能给我任何关于在方法中组合一些 LINQ 查询的建议,我将不胜感激;特别是主查询中的'排除' IQueryable 集合(请参阅评论)。
目前该查询的性能并不是特别好,如果您能提供任何建议以从代码角度提高其性能,我们将不胜感激。
在 Code Review 上收到的评论更具架构性,但是我目前无法将任何内容移动到数据库。
我很欣赏这是一个很大的方法,但我已经发布了全部内容来提供上下文。
预先感谢您提供的任何建议。
方法
/// Get templates by username and company
public List<BrowsingSessionItemModel> GetItemBrowsingSessionItems(
int companyId,
string userName,
Boolean hidePendingDeletions,
Boolean hideWithAppointmentsPending,
Boolean hideWithCallBacksPending,
int viewMode,
string searchString,
List<int?> requiredStatuses,
List<int?> requiredSources,
string OrderBy,
BrowsingSessionLeadCustomField fieldFilter)
{
try
{
IQueryable<Lead> exclude1;
IQueryable<Lead> exclude2;
IQueryable<Lead> exclude3;
//To prepare call backs pending
if (hideWithCallBacksPending == true)
{
exclude1 = (from l1 in db.Leads
where (l1.Company_ID == companyId)
from l2 // Hiding Pending Call Backs
in db.Tasks
.Where(o => (o.IsCompleted ?? false == false)
&& (o.TaskType_ID == (int)RecordEnums.TaskType.PhoneCall)
&& (o.Type_ID == (int)RecordEnums.RecordType.Lead)
&& (o.Item_ID == l1.Lead_ID)
&& (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1))
)
select l1);
}
else
{
exclude1 = (from l1 in db.Leads
where (0 == 1)
select l1);
}
//To prepare appointments backs pending
if (hideWithAppointmentsPending == true)
{
exclude2 = (from a1 in db.Leads
where (a1.Company_ID == companyId)
from a2 // Hiding Pending Appointments
in db.Tasks
.Where(o => (o.IsCompleted ?? false == false)
&& (o.TaskType_ID == (int)RecordEnums.TaskType.Appointment)
&& (o.Type_ID == (int)RecordEnums.RecordType.Lead)
&& (o.Item_ID == a1.Lead_ID)
&& (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1))
)
select a1);
}
else
{
exclude2 = (from a1 in db.Leads
where (0 == 1)
select a1);
}
//To prepare deletions
if (hidePendingDeletions == true)
{
exclude3 = (from d1 in db.Leads
where (d1.Company_ID == companyId)
from d2 // Hiding Pending Deletions
in db.LeadDeletions
.Where(o => (o.LeadId == d1.Lead_ID))
select d1);
}
else
{
exclude3 = (from d1 in db.Leads
where (0 == 1)
select d1);
}
// MAIN QUERY <--
IQueryable<Lead> list = (from t1 in db.Leads
from t2
in db.LeadSubOwners
.Where(o => t1.Lead_ID == o.LeadId && o.Expiry >= DateTime.Now)
.DefaultIfEmpty()
where (t1.Company_ID == companyId)
where ((t2.Username == userName) && (viewMode == 1)) || ((t1.Owner == userName) && (viewMode == 1)) || ((viewMode == 2)) // Either owned by the user or mode 2 (view all)
select t1).Except(exclude1).Except(exclude2).Except(exclude3);
// Filter sources and statuses seperately
if (requiredStatuses.Count > 0)
{
list = (from t1 in list
where (requiredStatuses.Contains(t1.LeadStatus_ID))
select t1);
}
if (requiredSources.Count > 0)
{
list = (from t1 in list
where (requiredSources.Contains(t1.LeadSource_ID))
select t1);
}
// Do custom field filter here
if (fieldFilter != null)
{
string stringIntegerValue = Convert.ToString(fieldFilter.IntegerValue);
switch (fieldFilter.FieldTypeId)
{
case 1:
list = (from t1 in list
from t2
in db.CompanyLeadCustomFieldValues
.Where(o => t1.Lead_ID == o.Lead_ID && fieldFilter.TextValue == o.LeadCustomFieldValue_Value)
select t1);
break;
case 2:
list = (from t1 in list
from t2
in db.CompanyLeadCustomFieldValues
.Where(o => t1.Lead_ID == o.Lead_ID && stringIntegerValue == o.LeadCustomFieldValue_Value)
select t1);
break;
default:
break;
}
}
List<Lead> itemsSorted; // Sort here
if (!String.IsNullOrEmpty(OrderBy))
{
itemsSorted = list.OrderBy(OrderBy).ToList();
}
else
{
itemsSorted = list.ToList();
}
var items = itemsSorted.Select((x, index) => new BrowsingSessionItemModel
{
Id = x.Lead_ID,
Index = index + 1
});
return items.ToList();
}
catch (Exception ex)
{
logger.Info(ex.Message.ToString());
return new List<BrowsingSessionItemModel>();
}
}
I posted this code snippet over at Stack Exchange's Code Review (beta) in order to obtain some feedback on how best to refactor a multi-part LINQ
query.
Being relatively new to LINQ
, I'm not really sure where to begin with this query.
If anybody could give me any advice on combining a few of the LINQ queries within the method, I'd appreciate it; especially the 'exclude' IQueryable collections into the main query (see comments).
The query is not particularly performant at the moment and any advice you could give in order to improve its performance from a code perspective would be appreciated.
The comments received on Code Review were more architectural, however I'm not currently in a position where I can move anything to the database at this time.
I appreciate it's a large method, but I've posted the whole lot to give context.
Thanks in advance for any advice you're able to give.
The Method
/// Get templates by username and company
public List<BrowsingSessionItemModel> GetItemBrowsingSessionItems(
int companyId,
string userName,
Boolean hidePendingDeletions,
Boolean hideWithAppointmentsPending,
Boolean hideWithCallBacksPending,
int viewMode,
string searchString,
List<int?> requiredStatuses,
List<int?> requiredSources,
string OrderBy,
BrowsingSessionLeadCustomField fieldFilter)
{
try
{
IQueryable<Lead> exclude1;
IQueryable<Lead> exclude2;
IQueryable<Lead> exclude3;
//To prepare call backs pending
if (hideWithCallBacksPending == true)
{
exclude1 = (from l1 in db.Leads
where (l1.Company_ID == companyId)
from l2 // Hiding Pending Call Backs
in db.Tasks
.Where(o => (o.IsCompleted ?? false == false)
&& (o.TaskType_ID == (int)RecordEnums.TaskType.PhoneCall)
&& (o.Type_ID == (int)RecordEnums.RecordType.Lead)
&& (o.Item_ID == l1.Lead_ID)
&& (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1))
)
select l1);
}
else
{
exclude1 = (from l1 in db.Leads
where (0 == 1)
select l1);
}
//To prepare appointments backs pending
if (hideWithAppointmentsPending == true)
{
exclude2 = (from a1 in db.Leads
where (a1.Company_ID == companyId)
from a2 // Hiding Pending Appointments
in db.Tasks
.Where(o => (o.IsCompleted ?? false == false)
&& (o.TaskType_ID == (int)RecordEnums.TaskType.Appointment)
&& (o.Type_ID == (int)RecordEnums.RecordType.Lead)
&& (o.Item_ID == a1.Lead_ID)
&& (o.Due_Date > EntityFunctions.AddDays(DateTime.Now, -1))
)
select a1);
}
else
{
exclude2 = (from a1 in db.Leads
where (0 == 1)
select a1);
}
//To prepare deletions
if (hidePendingDeletions == true)
{
exclude3 = (from d1 in db.Leads
where (d1.Company_ID == companyId)
from d2 // Hiding Pending Deletions
in db.LeadDeletions
.Where(o => (o.LeadId == d1.Lead_ID))
select d1);
}
else
{
exclude3 = (from d1 in db.Leads
where (0 == 1)
select d1);
}
// MAIN QUERY <--
IQueryable<Lead> list = (from t1 in db.Leads
from t2
in db.LeadSubOwners
.Where(o => t1.Lead_ID == o.LeadId && o.Expiry >= DateTime.Now)
.DefaultIfEmpty()
where (t1.Company_ID == companyId)
where ((t2.Username == userName) && (viewMode == 1)) || ((t1.Owner == userName) && (viewMode == 1)) || ((viewMode == 2)) // Either owned by the user or mode 2 (view all)
select t1).Except(exclude1).Except(exclude2).Except(exclude3);
// Filter sources and statuses seperately
if (requiredStatuses.Count > 0)
{
list = (from t1 in list
where (requiredStatuses.Contains(t1.LeadStatus_ID))
select t1);
}
if (requiredSources.Count > 0)
{
list = (from t1 in list
where (requiredSources.Contains(t1.LeadSource_ID))
select t1);
}
// Do custom field filter here
if (fieldFilter != null)
{
string stringIntegerValue = Convert.ToString(fieldFilter.IntegerValue);
switch (fieldFilter.FieldTypeId)
{
case 1:
list = (from t1 in list
from t2
in db.CompanyLeadCustomFieldValues
.Where(o => t1.Lead_ID == o.Lead_ID && fieldFilter.TextValue == o.LeadCustomFieldValue_Value)
select t1);
break;
case 2:
list = (from t1 in list
from t2
in db.CompanyLeadCustomFieldValues
.Where(o => t1.Lead_ID == o.Lead_ID && stringIntegerValue == o.LeadCustomFieldValue_Value)
select t1);
break;
default:
break;
}
}
List<Lead> itemsSorted; // Sort here
if (!String.IsNullOrEmpty(OrderBy))
{
itemsSorted = list.OrderBy(OrderBy).ToList();
}
else
{
itemsSorted = list.ToList();
}
var items = itemsSorted.Select((x, index) => new BrowsingSessionItemModel
{
Id = x.Lead_ID,
Index = index + 1
});
return items.ToList();
}
catch (Exception ex)
{
logger.Info(ex.Message.ToString());
return new List<BrowsingSessionItemModel>();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不明白为什么这样:
然后:
然后对于排除 1 和 2:
使用以下 GetExclude 方法:
Exclude3:
排除 1 和 2 可以被称为内联,因为它们很短:
I don't understand why this:
And that:
Then for excludes 1 and 2:
using the following GetExclude method:
Exclude3:
Excludes 1 and 2 can be called inline as they are short: