我有两个表: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将在那里设置。
如果没有以相同的方式设置我的表,是否有人可以查看代码并查看为什么我不保留该属性的值?
答案 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
语句的范围之外。