更新IEnumerable中的项目属性但该属性未保留设置?

时间:2012-02-01 22:16:33

标签: c# linq

我有两个表:Transactions和TransactionAgents。 TransactionAgents有一个名为TransactionID的Transactions的外键。很标准。

我也有这段代码:

BrokerManagerDataContext db = new BrokerManagerDataContext();

var transactions = from t in db.Transactions
                   where t.SellingPrice != 0 
                   select t;

var taAgents = from ta in db.TransactionAgents
               select ta;

foreach (var transaction in transactions)
{
    foreach(var agent in taAgents)
    {
        agent.AgentCommission = ((transaction.CommissionPercent / 100) * (agent.CommissionPercent / 100) * transaction.SellingPrice) - agent.BrokerageSplit;
    } 
}

dataGridView1.DataSource = taAgents;

基本上,TransactionAgent有一个名为AgentCommission的属性/列,对于我的数据库中的所有TransactionAgent都为null。

我的目标是执行您在foreach(var agent in taAgents)中看到的数学运算,以修补每个代理的值,使其不为空。

奇怪的是,当我在agent.AgentCommission = (formula)上运行此代码和断点时,它显示正在为AgentCommissision计算值并且对象正在更新,但在我的数据网格中显示(仅用于测试)后,它没有显示它计算的值。

所以,对我来说,似乎没有永久地在对象上设置属性。更重要的是,如果我通过更新将这个新更新的对象保留回数据库,我怀疑计算的AgentCommission将在那里设置。

如果没有以相同的方式设置我的表,是否有人可以查看代码并查看为什么我不保留该属性的值?

5 个答案:

答案 0 :(得分:85)

IEnumerable<T>保证更新的值将在枚举中保持不变。例如,List将在每次迭代时返回相同的对象集,因此如果更新属性,它将在迭代中保存。但是,IEnumerable的许多其他实现每次都会返回一组新对象,因此所做的任何更改都不会持久。

如果您需要存储和更新结果,请使用IEnumerable<T>List<T>向下拉到.ToList(),或使用IEnumerable<T>将其投影到新的.Select()应用了更改。

答案 1 :(得分:3)

具体来说,问题是每次访问IEnumerable时,它都会枚举整个集合。在这种情况下,集合是对数据库的调用。在第一部分中,您将从数据库中获取值并更新它们。在第二部分中,您将再次从数据库中获取值并将其设置为数据源(或者,迂腐地,您将枚举数设置为数据源,然后从数据库中获取值)。

使用.ToList()或类似方法将结果保存在内存中,并且每次都访问相同的集合。

答案 2 :(得分:3)

假设您正在使用LINQ to SQL,如果EnableObjectTracking为false,则每次运行查询时都会构造新对象。否则,您每次都会获得相同的对象实例,并且您的更改将继续存在。但是,正如其他人所示,不是让查询多次执行,而是将结果缓存到列表中。您不仅可以获得想要的工作,还可以减少数据库往返次数。

答案 3 :(得分:1)

我发现我必须在列表中找到我想要修改的项目,提取副本,修改副本(通过递增其count属性),从列表中删除原始内容并添加修改后的副本。                     var x = stats.Where(d =&gt; d.word == s).FirstOrDefault();                     var statCount = stats.IndexOf(x);                     x.count ++;                     stats.RemoveAt(statCount);                     stats.Add(X);

答案 4 :(得分:0)

使用 lambda 表达式重写 LINQ 表达式很有帮助,这样我们就可以更明确地考虑代码。

//Original code from question
var taAgents = from ta in db.TransactionAgents
               select ta;
//Rewritten to explicitly call attention to what Select() is actually doing
var taAgents = db.TransactionAgents.Select(ta => new TransactionAgents(/*database row's data*/)});

在重写的代码中,我们可以清楚地看到,Select() 正在根据从数据库返回的每一行构造一个新对象。更重要的是,这个对象构造每次都会发生,IEnumerable taAgents 被迭代。

所以,更具体地说,如果数据库中有 5 个 TransactionAgents 行,在下面的例子中,TransactionAgents() 构造函数总共被调用了 10 次。

// Assume there are 5 rows in the TransactionAgents table
var taAgents = from ta in db.TransactionAgents
               select ta;

//foreach will iterate through the IEnumerable, thus calling the TransactionAgents() constructor 5 times
foreach(var ta in taAgents)
{
  Console.WriteLine($"first iteration through taAgents - element {ta}");
}
// these first 5 TransactionAgents objects are now out of scope and are destroyed by the GC


//foreach will iterate through the IEnumerable, thus calling the TransactionAgents() constructor 5 MORE times
foreach(var ta in taAgents)
{
  Console.WriteLine($"second iteration through taAgents - element {ta}");
}

// these second 5 TransactionAgents objects are now out of scope and are destroyed by the GC

如我们所见,我们的所有 10 个 TransactionAgents 对象都是由 Select() 方法中的 lambda创建,并且不是 em> 存在于 foreach 语句的范围之外。