2

I have a WebApi application and i am working on some POST/PUT methods and i am trying to figure out the optimal way of updating a record in the database using entity framework.

The main issue with using WebApi is the request will only have a subset of the full properties of the full object.

For instance, i have a Site object that has a Project navigation object that points to the related project. As currently sites cannot move projects, i don't supply the projectId with the PUT command meaning that Project object of Site is empty, which causes issues when trying to update (even when stating that that property is not modified), so i have been forced to reading the record first and then merging the changes and then persisting, like:

Clarity for the example below, site is the object passed as a parameter to the PUT route so in this case is the partial Site object

//Grab the existing site
var dbSite = (from s in _repo
                       where s.Id == id
                       select s).FirstOrDefault();

//Update unchanged values
site.Id = id;
site.CreatedOn = dbSite.CreatedOn;

var entry = _uow.Entry(dbSite);
entry.Property(e => e.Code).IsModified = true;
entry.Property(e => e.Active).IsModified = true;
entry.Property(e => e.CreatedOn).IsModified = false;

_uow.Entry(dbSite).CurrentValues.SetValues(site);

//Commit
_uow.Commit();

Is there a way with taking a partial object (without certain navigation properties set) and updating the database without loading it first, or is the best approach loading it and updating the way i am doing it currently?

Modika
  • 6,192
  • 8
  • 36
  • 44
  • possible duplicate of http://stackoverflow.com/questions/4218566/update-a-record-without-first-querying?rq=1 – Matten Aug 13 '13 at 14:46
  • Not sure if I understand it right, but you can always use the _uow.Entity.Attach(dbSite) and set the entity state to modified. – Nilesh Aug 13 '13 at 14:46
  • 1
    @nilesh but his object is partially populated which causes EF validation errors. SO Attach would not work alone. – Varun K Aug 13 '13 at 14:49
  • @Matten the concept is similar (and i did read that question) but this is more about working with WebAPI where the serialised object from a PUT would not be complete and handling the update of that. Also, Attach doesn't work for me here. – Modika Aug 13 '13 at 14:49
  • I rushed in writing the comment. Sorry about that. I was going to ask whether your object has properties other than the ones shown in the post. – Nilesh Aug 13 '13 at 14:52
  • 1
    Regular EF doesn't have a way to do this, but [EntityFramework.Extended](https://github.com/loresoft/EntityFramework.Extended) was designed to address that. Worth a look, perhaps. – anaximander Aug 13 '13 at 14:53
  • @anaximander +1 for an alternative, will take a look – Modika Aug 13 '13 at 14:55
  • Try this [link](http://stackoverflow.com/questions/3642371/how-to-update-only-one-field-using-entity-framework) – Nilesh Aug 13 '13 at 14:55
  • @anaximander How does the Extended address this particular issue? – Mikael Östberg Aug 13 '13 at 14:57
  • @Nilesh, had a look, thing is my object has several navigation properties which are causing the issue. If I had simple objects I don't think I would have any issues. – Modika Aug 13 '13 at 14:57
  • Just trying to understand! What is the issue? Cant you attach the entity and just specify what properties are modified? Why would navigation properties be an issue? – Nilesh Aug 13 '13 at 15:02
  • @MikaelÖstberg It adds methods like `.Update()` that take lambda expressions describing the change to make to the item, which generate actual `UPDATE item FROM table WHERE condition` SQL, which regular EF doesn't quite do currently (EF does the update `WHERE id = @id`, essentially). – anaximander Aug 13 '13 at 15:05
  • @Nilesh, For instance, if i take the partial object, it doesn't have a project associated. I attach the site, but when i try and commit it, i receive an error which i think is related to the project entity as i can get over this error by loading the project and attaching that separately, either way i have to load something. – Modika Aug 13 '13 at 15:27

1 Answers1

0

You've discovered that you need more normalization in your entities as you have a logical relationship between Site and Project, but the relationship is not always needed.

To get the granularity of the entities that you want, you'll have to change the direct relationship between Site and Project to a many-to-many cross reference table so that you can work on a Site without any ties to Project.

Site: ID

SiteProjectRef: SiteID (Site.ID) ProjectID (Project.ID)

Project: ID


The alternative is, of course, to load the Site and merge the contents before updating. But you stated that you didn't want to go there.

Keith Payne
  • 3,002
  • 16
  • 30
  • I am not sure I understand. A site will always need a Project, it is bound to that in the application, and I wouldn't want to introduce a many-to-many structure for this. Also, i am not against, merging and loading (that is what i am doing) i was just trying to avoid the load if possible by attaching a partial object and then marking the navigation elements as not being modified so that they are untouched, which did not work. – Modika Aug 13 '13 at 15:24
  • I don't have knowledge of the domain at all, but the example that you gave tells me that a `Site` does not need a `Project` *all of the time* - as when the `Site` is being edited as you described... – Keith Payne Aug 13 '13 at 16:22
  • It is easier to see if you replace the surrogate keys with natural keys. Assume- `Site` has a *location*, which is its natural key; `Project` has a *name*, which is its natural key. `Site` also contains the `Project.Name` as a foreign key. However, when editing the `Site` in the way that you describe, the user has no concept of the `Project` and is not even viewing the `Project` name while editing. So `Site` *can* exist independent of the `Project`. – Keith Payne Aug 13 '13 at 16:22
  • Hi Keith, The site is bound to a project, that's the relationship. The reason I don't need one when updating is because the Site is already assigned one, so i simply want EF to ignore it when updating. Not sure adding complexity to the model is the way to go, i think i would rather stick to what is already there with loading and updating. – Modika Aug 13 '13 at 17:11