I have implemented a sort of Repository
class and it has has GetByID
, DeleteByID
methods and so on, but I'm having trouble implementing the UpdateByID
method.
I did something like this:
public virtual void UpdateByID(int id, T entity)
{
var dbcontext = DB;
var item = GetByID(dbcontext, id);
item = entity;
dbcontext.SubmitChanges();
}
protected MusicRepo_DBDataContext DB
{
get
{
return new MusicRepo_DBDataContext();
}
}
But it's not updating the passed entity.
Has anyone implemented such a method ?
For reference, here is the GetByID
method
[Update]
As Marc correctly suggested, I am merely changing the values of the local variable. So how do you think I should go about this method? Use reflection and copy the properties from entity
to item
?
Taking a fresh look here, previous answers to question made various assumptions about the application.
Concurrency within an application is something that needs to be thought about upfront and is something for which there isn't really a one-size-fits-all answer. Things to consider when making the choice for your application:
Different solutions have very different performance implications! You won't notice as you're developing but your app may fall over when 25 people use it simultaneously. Watch for lots of copying back and forth and for many SQL reads:
Here are some good links for deeper reading to decide your specific needs:
My recommended solution:
Where
REFRESH_MODE
specifies one of the following:RefreshMode.KeepChanges
RefreshMode.KeepCurrentValues
RefreshMode.OverwriteCurrentValues
You will also need to make some considerations about your model:
Probably goes without saying but you will need to let LINQ know which field is your primary key to update the entities. You don't have to pass this in as another param (as in your original method) because LINQ already knows this is the PK.
You get to (rather than "have to") decide which fields are actually checked. For instance a foreign key field is very important to have concurrency checking, whereas the description field probably deserves a last-one-wins. You control that via the
UpdateCheck
attribute. The default isUpdateCheck.Always
. From MSDN:To enable optimistic concurrency, you need to specify a field to use as the concurrency token (e.g. timestamp or version) and this field always has to be present when serializing back and forth. Mark this column with
IsVersion=true
.If you don't want concurrency checking then you must mark all as UpdateCheck.Never.
Hey dreas, I've also struggled with this and found a very elegant solution.
You essentially have to use the DataContext.Attach(EntityToUpdate,OriginalEntity) method.
There are a few gotchas...so, read this information, it will explain everything.
Once you've read it, just come back to me with any questions. I've written a really useful EntitySaver Class based on that info, so if you need, we can go through your Class once you get the gotchas.
cheers
EDIT: here's my Class in full, in case you want to try it out. It actually handles Updates and Inserts automatically. let me know of you have any questions.
Entity Saver:
You'll need these helpers too:
and these extensions make reflection easier:
I'm not very familiar with repository patterns but what if you delete the old entity from the database, and put the new entity in the database with the same ID? something like this:
Well I have something like this (from the top of my head):
It works ok for simple entities. Of course if you have many entities you could use reflection.
If I'm understanding correctly, you shouldn't need reflection for this.
To do this for a specific entity you need to take your entity and attach it to the DB context. Once it is attached LINQ-to-SQL will determine what needs to be updated. Something along the lines of:
That would be for updating a Member in the Members table. The true argument says that you modified it. Alternatively if you had the original lying around you could pass that in as the second argument and let the DB context perform the diff for you. That is a major part of the DB context implementation (which implements the "Unit of Work" pattern).
To generalize this, you would replace the Member type with T, and replace the .Members with .GetTable:
Assuming that the ID is already set correctly on the entity (and that it is marked as a primary key in the model), you don't even need to look it up first. If you feel the need, you could look it up by ID and then pass it into the Attach method, but this probably just causes an extra lookup that isn't needed.
EDIT: You need to set UpdateCheck to Never on your columns in the model, otherwise it tries to perform concurrency checking. You will get a last update wins if you set it to Never. Otherwise you add tmestamp fields to your tables and the concurrency checking will determine if the entity is out of date or not.
UpdateCheck.Never combined with Attach(entity, bool) will be the simplest and most performant way to solve this with LINQ-to-SQL.
I had some similar issues and ended up going with PLINQO, lots of enhancements to the LINQ-TO-SQL generated code. However it does require a CodeSmith purchase (although free to eval for 30 days) if you don't already have it.