性能不佳的查询需要重写

时间:2013-02-20 09:45:52

标签: c# linq-to-entities

我有一段代码表现不佳,需要重新编写它以在启动.ToList之前引入正确的where子句但是,这就是我陷入困境的地方。

目前代码看起来像这样(粗略地说,我已经采取了一些搜索标准,以便更容易显示)

var Widgets = from b in _caspEntities.Widgets.Include("WidgetRegionLogs")
                    .Include("WidgetStatusLogs").Include("WidgetVoltageTests")
                        select b;

IEnumerable<Widget> results = Widgets.ToList();
if (comboBoxRegion.SelectedValue.ToString() != "0")
{
    results = from b in results
              where b.CurrentRegionLog != null && b.CurrentRegionLog.RegionId == int.Parse(comboBoxRegion.SelectedValue.ToString())
              select b;
}

if (comboBoxStatus.SelectedValue != null)
{
    results = from b in results
              where b.CurrentStatusLog != null && b.CurrentStatusLog.StatusId == comboBoxStatus.SelectedValue.ToString()
              select b;
}

if (txtCode.Text.Trim().Length > 0)
{
    results = from b in results
              where b.CodeNumber == txtCode.Text.Trim()
              select b;
}

dataGridViewWidget.DataSource = results.ToList();

我可以很容易地编写SQL,本质上模型很简单,我有一个Widget它有一个RegionLog和一个StatusLog,它们都存储一个历史记录。通过按WidgetID分组并选择最近更新的日期(然后转到Region和Status表以获取实际值),从中检索当前区域和状态。

所以,我需要把它翻译成LINQ,但说实话,我没有线索,但是肯定并且愿意学习。在我的脑海中,我想我需要添加一些更好的where子句,然后在我应用where子句后执行Widget.toList。我正在努力处理CurrentRegionLogCurrentStatusLog概念,因为在我运行IEnumerable之前它们没有填充。

如果有人能指点一下,我将不胜感激, 感谢

编辑 - 添加

    public BatteryRegionLog CurrentRegionLog
    {
        get { return _currentRegionLog; }
    }

    private BatteryRegionLog _currentRegionLog
    {
        get
        {
            if (this.BatteryRegionLogs.Count > 0)
            {
                BatteryRegionLog log = this.BatteryRegionLogs.OrderByDescending(item =>    item.LastModifiedDate).First();
                return log;
            }
            else
            {
                return null;
            }
        }
    }

2 个答案:

答案 0 :(得分:0)

尝试删除此行:

IEnumerable<Widget> results = Widgets.ToList();

并使用您在顶部

中获得的Widgets变量

.ToList()转到数据库并将所有数据实质化为实体。

如果您不致电.ToList(),则where条款的查询仍然“开放”

答案 1 :(得分:0)

您可以像这样编写查询:

    if (comboBoxRegion.SelectedValue.ToString() != "0")
    {
        var id = int.Parse(comboBoxRegion.SelectedValue.ToString()
        Widgets = from b in Widgets
                  let currentRegionLog = 
                        b.BatteryRegionLogs
                         .OrderByDescending(item => item.LastModifiedDate)
                         .FirstOrDefault()
                  where currentRegionLog.RegionId == id)
                  select b;
    }
    ... // Same for the other criteria.

    dataGridViewWidget.DataSource = Widgets.ToList();

在执行ToList()之前,不会执行整个查询。当所有内容都转换为SQL时,您不需要空检查b.CurrentRegionLog != null。当没有b.CurrentRegionLog.RegionId == id时,SQL会评估CurrentRegionLog

修改

由于CurrentRegionLogWidget类的计算属性,因此无法将其转换为SQL。我努力将计算属性的代码以只使用基本导航属性的方式合并到查询中,因此EF可以再次将其转换为SQL。