tags:

views:

101

answers:

5

I am trying to do an update in Linq.

public myFunc(MyItem newItem)
{
  using(var db = new myDataContext())
  {
     var item = (from o in db.myTable where o.id == myId select o).First();
     item = newItem;
     db.SubmitAllChanges();
  }
}

This doesn't update the object, I guess item = newItem changes item to refer to the other. If I change the individual fields (item.Name = newItem.Name etc.) te change is reflected, however I don't want to spread the contents of the MyItem class into multiple places to reduce maintainability. Is there some way to make the item=newItem copy on a field by field basis?

Also MyItem has a relationship to another table, and I want to update the subordinate items from newItem into item too. (FWIW, there are no adds or deletes, just updates.) Is there a standardized process for doing this?

Thanks for you help.

+4  A: 

You can't just assign newItem to item. When you assign newItem to item, it simply points item to a new location in memory...it doesn't actually update anything on the entity.

You need to go through and assign each property individually:

using(var db = new myDataContext())
{
    var item = db.myTable.First(o => o.id == myId);
    item.Prop1 = newItem.Prop1;
    item.Prop2 = newItem.Prop2;
    // etc
}

A better option would be to extend the partial class (as mentioned by Jon Skeet) from the Entity Model and make this a method (so you can re-use the code).

Justin Niessner
+6  A: 

Well, MyItem should be a partial class - so you could add a CopyPropertiesFrom method to MyItem, and then write

item.CopyPropertiesFrom(newItem);

instead of your current assignment.

By the way, you might want to consider using this instead of your current query:

var item = db.myTable.First(o => o.id == myId);

Just makes things a bit simpler than a query expression in this case :)

Jon Skeet
It seems to me that this is a really common process. Isn't there an automatic way to do this?BTW, great tip on the LINQ query. I do this sort of thing all the time and yours is so much more concise. undoubtedly your suggestion will significantly impact the way I write code... so thanks.
Mike Jones
@Mike: I don't think it's *particularly* common. Normally if you want to update an entity wholesale, you'd fetch it first, edit it, then reattach.
Jon Skeet
That is an interesting comment, I thought about it in the context of my code. Why I have to do it is that the item is edited in JavaScript on the client side, then submitted as a JSON. The JSON is decoded and that object is the "newItem" in my example.Is there perhaps a better approach to this?
Mike Jones
@Mike: In that case you might just want to change how you decode the JSON, if possible: fetch the item, then decode the JSON "into" the existing item. It depends on how you're dealing with the JSON though.
Jon Skeet
A: 

give it the same key and do an attach followed by a submitchanges....

Tim Mahy
I tried to do an attach, viz: db.myTable.Attach(newItem);However this gives a duplicate key error. Do I have to delete the item first? That seems a little backward?
Mike Jones
+2  A: 

I think you should gain some understanding of basic concepts of C# variables and references first.

Types in C# are divided into two groups: reference types and value types. They are different in many aspects, and copying and comparing is one of these aspects.

Value types include simple types like int (watch out: string is not a value type though you might think so), enumerations and structures. They get copied when you reassign values to different variables, pass them as parameters etc.

By saying

int x = 5;
int y = 7;
x = y;

You assign the value of y to x, which results in x being equal to 7.
However, if you change y further, x won't get updated:

int x = 5;
int y = 7;
x = y; // 7
y = 10; // x is still 7

On the contrary, reference types don't get copied on assignment. It's only references that get copied.

MyItem john = new Customer("John");
MyItem jack = new Customer("Jack");
jack = john; // now both references point to the same Customer

In this code snippet we forgot about Customer called "Jack" and both jack and john now point to the same object with name "John".

Therefore, by saying

item = newItem;

you only make item point to the object referenced by newItem at that moment (or null if it was empty).

You might want to define an Assign method in your class that performs the routine of assignment:

public void Assign(MyItem that)
{
    this.Name = that.Name;
    this.City = that.City;

    // etc
}

At some point, you might also want to write an extension method that uses reflection to assign all public properties—but that's a good topic for a different question (which most likely has already been asked and answered several times).

gaearon
A: 

An alternative option would be to use AutoMapper to automatically copy the values for you.

Above said, in many cases a simple method in a partial class would do just well (like in Jon Skeet answer).

eglasius