C# 更新 IEnumerable 中的项目属性但该属性未设置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9104181/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 05:57:47  来源:igfitidea点击:

Updating an item property within IEnumerable but the property doesn't stay set?

c#linq

提问by Isaiah Nelson

I have two tables: Transactions and TransactionAgents. TransactionAgents has a foreign key to Transactions called TransactionID. Pretty standard.

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

I also have this code:

我也有这个代码:

BrokerManagerDataContext db = new BrokerManagerDataContext();

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;

Basically, a TransactionAgent has a property/column named AgentCommission, which is null for all TransactionAgents in my database.

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

My goal is to perform the math you see in the foreach(var agent in taAgents)to patch up the value for each agent so that it isn't null.

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

Oddly, when I run this code and break-point on agent.AgentCommission = (formula)it shows the value is being calculated for AgentCommissision and the object is being updated but after it displays in my datagrid (used only for testing), it does not show the value it calculated.

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

So, to me, it seems that the Property isn't being permanently set on the object. What's more, If I persist this newly updated object back to the database with an update, I doubt the calculated AgentCommission will be set there.

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

Without having my table set up the same way, is there anyone that can look at the code and see why I am not retaining the property's value?

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

采纳答案by eouw0o83hf

IEnumerable<T>s do not guaranteethat updated values will persist across enumerations. For instance, a Listwill return the same set of objects on every iteration, so if you update a property, it will be saved across iterations. However, many other implementations of IEnumerables return a new set of objects each time, so any changes made will not persist.

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

If you need to store and update the results, pull the IEnumerable<T>down to a List<T>using .ToList()or project it into a new IEnumerable<T>using .Select()with the changes applied.

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

To specifically apply that to your code, it would look like this:

要将其专门应用于您的代码,它看起来像这样:

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

var taAgents = (from ta in db.TransactionAgents
                select ta).ToList();

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;

回答by Kyle W

Specifically, the problem is that each time you access the IEnumerable, it enumerates over the collection. In this case, the collection is a call to the database. In the first part, you're getting the values from the database and updating them. In the second part, you're getting the values from the database again and setting that as the datasource (or, pedantically, you're setting the enumerator as the datasource, and then that is getting the values from the database).

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

Use .ToList() or similar to keep the results in memory, and access the same collection every time.

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

回答by Matt Warren

Assuming you are using LINQ to SQL, if EnableObjectTracking is false, then the objects will be constructed new every time the query is run. Otherwise, you would be getting the same object instances each time and your changes would survive. However, like others have shown, instead of having the query execute multiple times, cache the results in a list. Not only will you get what you want working, you'll have fewer database round trips.

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

回答by David

I found that I had to locate the item in the list that I wanted to modify, extract the copy, modify the copy (by incrementing its count property), remove the original from the list and add the modified copy. var x = stats.Where(d => d.word == s).FirstOrDefault(); var statCount = stats.IndexOf(x); x.count++; stats.RemoveAt(statCount); stats.Add(x);

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