简体   繁体   中英

How do I update an existing entity with data via Linq-to-XML?

I am using Linq-to-Xml to read XML and update an existing data structure. Right now I have the following code to do this:

        // Load all the test plan details
        var details = doc.Descendants()
                         .Select(x => new
                         {
                             Name = x.Attribute("name").ToStringValue(),
                             DbName = x.Attribute(DATABASE_ATTR).ToStringValue(),
                             Login = x.Attribute(USERNAME_ATTR).ToStringValue(),
                             Password = x.Attribute(PASSWORD_ATTR).ToStringValue(),
                             AppSource = x.Attribute(APPSOURCE_ATTR).ToStringValue()
                         })
                         .First();


        testPlan.Name = details.Name;
        testPlan.DatabaseName = details.DbName;
        testPlan.LoginUsername = details.Login;
        testPlan.LoginPassword = details.Password;
        testPlan.ApplicationSource = details.AppSource;
    }

This is kind of annoying to me because I have to create a temp variable and perform the data transfer. Is there any way for me to update the testPlan variable straight from within the Linq statement, which would cut down one step? I could not get it to work by adding the update code into the .Select() statement.

The following should work:

doc.Descendants().First()
   .Select(x => 
           {
               testPlan.Name= x.Attribute("name").ToStringValue();
               testPlan.DatabaseName = x.Attribute(DATABASE_ATTR)
                                        .ToStringValue();
               testPlan.LoginUsername = x.Attribute(USERNAME_ATTR)
                                         .ToStringValue();
               testPlan.LoginPassword = x.Attribute(PASSWORD_ATTR)
                                         .ToStringValue();
               testPlan.ApplicationSource = x.Attribute(APPSOURCE_ATTR)
                                             .ToStringValue();
               return testPlan;
           })
    .ToList();

The call to First in the middle is to ensure, that only the attributes of the first descendant will be assigned to the properties of testPlan . The ToList at the end is used to really execute the code inside Select .

Although this works, I don't recommend using it, because it uses LINQ in a way it wasn't created for. Furthermore, it's easy to create it wrong:

  • If you forget the First , testPlan will contain the attribute values of the last element in your XML, because the select code is executed for each element and overwrites the properties.
  • If you forget the call to ToList or a similar method that forces the execution, the code inside Select will never be executed.

So, basically, the problem is, that you create a lot of possibilities to introduce a bug.

I would implement something like this in the following way:

var x = doc.Descendants.First();
testPlan.Name= x.Attribute("name").ToStringValue();
testPlan.DatabaseName = x.Attribute(DATABASE_ATTR).ToStringValue();
testPlan.LoginUsername = x.Attribute(USERNAME_ATTR).ToStringValue();
testPlan.LoginPassword = x.Attribute(PASSWORD_ATTR).ToStringValue();
testPlan.ApplicationSource = x.Attribute(APPSOURCE_ATTR).ToStringValue();

This is shorter, easier to read and doesn't violate LINQ to do something it wasn't created for.

What I would do is create a constructor in the TestPlan class that takes a argument of type details?

Then just call testPlan = new TestPlan(details);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM