【问题标题】:Using Entity Framework, which method is more efficient?使用实体框架,哪种方法更高效?
【发布时间】:2012-06-15 04:53:00
【问题描述】:

我有一些代码可以在循环中更改数据库中某些数据的值。我只是想知道首先过滤数据的最有效方法是什么?我举个例子:-

与类:-

public class myObj 
{
    int id {get;set;}
    string product {get; set;}
    string parent{get;set;}
    bool received {get;set;}
}

还有 DbContext:-

public class myCont:DbContext
{
    public DbSet<myObj> myObjs {get;set;}
}

这样做更好吗:-

int[] list;
/* Populate list with a bunch of id numbers found in myOBjs */
myCont data = new myCont();
myObj ob = data.myObjs.Where(o => o.parent == "number1");
foreach(int i in list)
{
    ob.First(o => o.id == i && o.received != true).received = true;
}

或者:-

int[] list;
/* Populate list with a bunch of id numbers found in myOBjs */
myCont data = new myCont();
foreach(int i in list)
{
    data.myObjs.First(o => o.parent == "number1" && o.id == i && o.received != true).received = true;
}

还是没有区别?

【问题讨论】:

  • 你可以使用sql profile来检查linq生成的命令
  • 只有代码遍历IQueryable时才会生成sql查询。 EF 推迟执行,直到需要物化一个对象。
  • 小的可读性改进:ob.First(o =&gt; o.id == i &amp;&amp; o.received != true).received = true;
  • @JohnPolvora 我怀疑它可能会这样工作。
  • 没有区别。第一个示例中的obIQueryable,并且在两个代码sn-ps 中每次迭代都会执行一次相同的查询(因此,list.Count() 次)。 @Asif 的答案中可能会提高性能(即只有一个数据库查询,然后在内存中进行迭代)(无论出于何种奇怪原因,它现在已被否决并删除)。

标签: c# linq entity-framework


【解决方案1】:

不确定如何编译上面的代码示例。

在您的myObj 对象中,received 属性是一个int,但您正在根据bool 对其进行评估,这应该会导致此行o.received != true 导致错误Cannot apply operator '!=' to operands of type 'int' and 'bool'

检查 SQL
代码编译完成后,使用SQL Profiler 查看生成的 SQL。

这将向您展示构造的 SQL

基准测试
以下是对您可以对代码执行进行基准测试的唯一一种可能的方法的非常粗略的描述。

将你的代码包装成一个方法,例如:

public void TestingOperationOneWay()
{
    int[] list;
    /* Populate list with a bunch of id numbers found in myOBjs */
    myCont data = new myCont();
    myObj ob = data.myObjs.Where(o => o.parent == "number1");
    foreach(int i in list)
    {
        ob.First(o => o.id == i && o.received != true).received = true;
    }
}

还有:

public void TestingOperationAnotherWay()
{
    int[] list;
    /* Populate list with a bunch of id numbers found in myOBjs */
    myCont data = new myCont();
    foreach(int i in list)
    {
        data.myObjs.First(o => o.parent == "number1" && o.id == i && o.received != true).received = true;
    }
}

使用类似于此的Stopwatch 创建一个在每个方法上迭代 x 次的方法:

private static TimeSpan ExecuteOneWayTest(int iterations)
{
    var stopwatch = Stopwatch.StartNew();

    for (var i = 1; i < iterations; i++)
    {
        TestingOperationOneWay();
    }

    stopwatch.Stop();

    return stopwatch.Elapsed;
}

评估类似这样的结果:

static void RunTests()
{
    const int iterations = 100000000;

    var timespanRun1 = ExecuteOneWayTest(iterations);
    var timespanRun2 = ExecuteAnotherWayTest(iterations);

    // Evaluate Results....
}

【讨论】:

  • 谢谢你,我不知道秒表对象。至于编译不好的代码,上面的代码不是来自我的项目,只是一些示例代码来演示我在我的应用程序中尝试做的事情,但也谢谢你。
【解决方案2】:

如果在您的两个查询之间进行选择,我同意它们的执行方式相似,并且基准测试是一种适当的响应。但是,您可以做一些事情来优化。例如,您可以使用方法 'AsEnumerable' 来强制使用 IEnumerable 'Where' 代替 LINQ 'Where' 子句(转换为 SQL 和针对数据源执行或处理对象层次结构中的 where 的区别)。由于您似乎只在操作属性(而不是实体关系),您可以这样做:

int[] list;
/* Populate list with a bunch of id numbers found in myOBjs */
myCont data = new myCont();
myObj ob = data.myObjs.Where(o => o.parent == "number1").AsEnumerable<myObj>();
foreach(int i in list)
{
    ob.First(o => o.id == i && o.received != true).received = true;
}

这样做可以避免为每条记录访问数据库的损失(可能避免网络延迟),但会增加内存占用。这是associated LINQ further explaining this idea。这实际上取决于您可以在哪里吸收性能成本。

【讨论】:

    猜你喜欢
    • 2019-11-22
    • 2016-05-17
    • 1970-01-01
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    • 1970-01-01
    • 2013-12-13
    相关资源
    最近更新 更多