none
Update specific values from one collection into other RRS feed

  • Question

  • Hello,

    I have below code:

    var personalizedData = "TransactionLocationID,Amount";
    
    
                List<SXARCMTransactionDetails> lstTransactions = new List<SXARCMTransactionDetails>();
                lstTransactions.Add(new SXARCMTransactionDetails() {TransactionID = 1, Amount =22,TransactionLocationID = 9 });
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 2, Amount = 23, TransactionLocationID = 10 });
    
                List<SXARCMTransactionDetails> lstTransactionsToUpdate = new List<SXARCMTransactionDetails>();
                lstTransactionsToUpdate.Add(new SXARCMTransactionDetails() { TransactionID = 1, Amount = 0, TransactionLocationID = 0 });
                lstTransactionsToUpdate.Add(new SXARCMTransactionDetails() { TransactionID = 2, Amount = 0, TransactionLocationID = 0 });

    I want to update the column values of all the rows in "lstTransactionsToUpdate" with values present in "lstTransactions". The name of the columns are there in "personalizedData" string.

    SXARCMTransactionDetails is nothing but a class which holds properties such as TransactionID, Amount, etc. TransactionID is an unique primary key which will be present in both the lists.

    Please let me know how this can be achieved.

    Below is the link to console app:

    https://drive.google.com/drive/folders/19Rt0OXcfJBRRTn5UNB9RzdBhx4npTxbQ?usp=sharing

    Abdi




    • Edited by abdi81 Thursday, March 5, 2020 2:27 PM
    Thursday, March 5, 2020 2:23 PM

All replies

  • You could do it like this : 

     foreach (SXARCMTransactionDetails updateItem in lstTransactionsToUpdate)
                {
                    SXARCMTransactionDetails item = lstTransactions.FirstOrDefault(_ =>
                        _.TransactionID.Equals(updateItem.TransactionID));
                    if (item != null)
                    {
                        updateItem.Amount = item.Amount;
                        updateItem.TransactionLocationID = item.TransactionLocationID;
                    }
                }


    but that is actually not really good code. For every item in the first list it needs to go through every item in the second list. Also in the if statement you need to assign all properties, if you add a property you must not forget to add it in this code also. That is a problem.

    If the secondlist contains the same transactionId's as the first list (and no more) than you could also simply do : 

    List<SXARCMTransactionDetails> lstTransactionsToUpdate =
                    new List<SXARCMTransactionDetails>(lstTransactions);


    If not all transactionId's are present in the second list, you may need to do something like this. 

    Dictionary<int, SXARCMTransactionDetails> updateDictionary = lstTransactionsToUpdate.ToDictionary(_ => _.TransactionID);
    
                foreach (SXARCMTransactionDetails item in lstTransactions)
                {
                    updateDictionary[item.TransactionID] = item;
                }
    
                lstTransactionsToUpdate = new List<SXARCMTransactionDetails>(updateDictionary.Values);

    But be aware if lstTransaction has items that lstTransactionsToUpdate has not, after this code that item will also be present in lstTransactionsToUpdate. If you don't want that you need to filter out the unwanted items like so :

    Dictionary<int, SXARCMTransactionDetails> updateDictionary = lstTransactionsToUpdate.ToDictionary(_ => _.TransactionID);
    
                foreach (SXARCMTransactionDetails item in lstTransactions.Where(_ => updateDictionary.ContainsKey(_.TransactionID)))
                {
                    updateDictionary[item.TransactionID] = item;
                }
    
                lstTransactionsToUpdate = new List<SXARCMTransactionDetails>(updateDictionary.Values);


    Hope this helps,

    Here to learn and share. Please tell if an answer was helpful or not at all. This adds value to the answers and enables me to learn more.

    About me

    Thursday, March 5, 2020 4:21 PM
  • Hi abdi81,

    Thank you for posting here.

    If every property of the element in lstTransactionsToUpdate will be modified, KeesDijk's solution is a good choice.

    Now, I assume that only some property will be modified. The properties that need to be modified are dynamic and stored in "personalizedData".

     static void Main(string[] args)
            {
                var personalizedData = "TransactionLocationID,Amount";
    
    
                List<SXARCMTransactionDetails> lstTransactions = new List<SXARCMTransactionDetails>();
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 1, Amount = 22, TransactionLocationID = 9 });
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 2, Amount = 23, TransactionLocationID = 10 });
    
                List<SXARCMTransactionDetails> lstTransactionsToUpdate = new List<SXARCMTransactionDetails>();
                lstTransactionsToUpdate.Add(new SXARCMTransactionDetails() { TransactionID = 1, Amount = 0, TransactionLocationID = 0 });
                lstTransactionsToUpdate.Add(new SXARCMTransactionDetails() { TransactionID = 2, Amount = 0, TransactionLocationID = 0 });
    
                
                foreach (SXARCMTransactionDetails updateItem in lstTransactionsToUpdate)
                {
                    SXARCMTransactionDetails item = lstTransactions.FirstOrDefault(_ =>
                        _.TransactionID.Equals(updateItem.TransactionID));
                    string[] properties  = personalizedData.Split(new char[] { ',' });
    
                    PropertyInfo[] propertyInfos = item.GetType().GetProperties();
                    for (int i = 0; i < properties.Length; i++)
                    {
                        foreach (var propertyInfo in propertyInfos)
                        {
                            if (propertyInfo.Name == properties[i])
                            {
                                updateItem.GetType().GetProperty(properties[i]).SetValue(updateItem,item.GetType().GetProperty(properties[i]).GetValue(item));
                            }
                        }
                    }
                }
            }

    This code part draws on KeesDijk's code.

    Hope this could be helpful.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.



    Friday, March 6, 2020 2:29 AM
  • Thanks Timon.

    Your solution does work but in my case, I have almost approximately 2000 rows in the lstTransactionsToUpdate and iterating 2-3 times in foreach/for alongwith using Reflection to fetch the property details; will have a large impact on Performance of application. Don't you think so?

    Regards,

    Abdi

    Friday, March 6, 2020 11:57 AM
  • Yes, I was thinking the same and started researching LINQ Update but the samples I found were for a single table.

    If you know all your properties of the object in advance, then you can probably just create boolean variables for each property and just create a single command that will update using either the first collection or the other depending on that boolean property (In T-SQL this update would be something like

    update myTable set prop = iif(@updateProp, @Prop, prop) )


    For every expert, there is an equal and opposite expert. - Becker's Law


    My blog


    My TechNet articles

    Friday, March 6, 2020 1:59 PM
    Moderator
  • Hi addi81,

    Yes, I agree.

    Nested loops and lots of reflections will affect program performance.

    I have a new idea to extract some attributes of the elements in "lstTransactions" to form a new list, and then assign them to the corresponding elements of "lstTransactionsToUpdate". The following is part of the code.

      var personalizedData = "TransactionLocationID,Amount";
                List<SXARCMTransactionDetails> lstTransactions = new List<SXARCMTransactionDetails>();
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 1, Amount = 22, TransactionLocationID = 9 });
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 2, Amount = 23, TransactionLocationID = 10 });
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 3, Amount = 23, TransactionLocationID = 10 });
                lstTransactions.Add(new SXARCMTransactionDetails() { TransactionID = 4, Amount = 23, TransactionLocationID = 10 });
    
                List<SXARCMTransactionDetails> lstTransactionsToUpdate = new List<SXARCMTransactionDetails>();
                lstTransactionsToUpdate.Add(new SXARCMTransactionDetails() { TransactionID = 1, Amount = 0, TransactionLocationID = 0 });
                lstTransactionsToUpdate.Add(new SXARCMTransactionDetails() { TransactionID = 2, Amount = 0, TransactionLocationID = 0 });
                string[] properties = personalizedData.Split(new char[] { ',' });
                PropertyInfo[] propertyInfos = typeof(SXARCMTransactionDetails).GetProperties();
    
                Dictionary<string, List<object>> keyValuePairs = new Dictionary<string, List<object>>();
                var transactionIDs = from pro in lstTransactionsToUpdate
                             select pro.TransactionID;
                foreach (var item in properties)
                {
                   
                    var result = from pro in lstTransactions
                                 where transactionIDs.Contains(pro.TransactionID)
                                 select pro.GetType().GetProperty(item).GetValue(pro);
                    keyValuePairs.Add(item, result.ToList());
                }

    But in the subsequent assignment process, we still need to use reflection and loop.

    I can't think of any good way to avoid it for now. Maybe someone can provide a better solution on this basis.

    Hope this could be helpful.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 9, 2020 6:16 AM