1

The architecture for my application is structured as follows:

UI (client-side)

User Interface (XAML)

VM (client-side)

The layer for all view models. This layer works with the DTOs from the service layer.

Service (server-side)

Communication interface for the client. The client consumes DTOs from this service layer. This layer does the transformation from DTOs to EF-Entities (and back). I do the transformation with the automapper.

Domain (server-side)

The whole businesslogic seperated in several domains. This layer works with the entities from the entity framework.

Data Acccess (server-side):

The data access layer works with the EF. This layer ist designed with the repository / unitofwork pattern.

My problem: The creation of a new record works well. But if I want to update a record, the EF doesn't know about the update. It always wants to create a new record. I assume, that the problem is, that the EF works with the references for the whole change-tracking mechanism. The automapper will always create a new record. Is this correct?

Are there any alternatives?

Thanks in advance.

Kind regards, pro

Edit: Summarization of my problem:

EF does not update in my n-layered architecture, it always wants to create a new record.

I hope that will help.

bitsmuggler
  • 1,689
  • 2
  • 17
  • 30
  • as I know you can update normally in finite element as an example context.SaveChanges() – AMH Jul 30 '12 at 08:32
  • You need to attach the entity. Have a look at this answer : http://stackoverflow.com/questions/3920111/entity-framework-4-addobject-vs-attach – mathieu Jul 30 '12 at 08:33
  • @mathieu: Thanks for your answer, but in my opinion this doesn't work, because the context are aware of the entity => it will throw an exception (multiple entities with the same id). – bitsmuggler Jul 30 '12 at 08:35
  • @AMH: Thanks for your answer. With SaveChanges method it will create a new record. I want to change the record. – bitsmuggler Jul 30 '12 at 08:36
  • Then your context lives for too long :) – mathieu Jul 30 '12 at 08:36
  • @mathieu: OK - I create per service one instance of a context. Is this bad? – bitsmuggler Jul 30 '12 at 08:37
  • @pro : updated my answer. TL;DR; version : dbcontext should be created and discarded when needed and not kept around. If your services are singletons, you may be in trouble, because so will be your contexts – mathieu Jul 30 '12 at 08:39
  • @mathieu: My services are normal wcf services (Instance per thread). And the ef-context will be created at initialization of this service. Should I create a dbcontext at each service call?? – bitsmuggler Jul 30 '12 at 08:41
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/14616/discussion-between-mathieu-and-pro) – mathieu Jul 30 '12 at 08:42
  • @mathieu: Sorry, I saw your comment too late.. – bitsmuggler Jul 30 '12 at 09:25
  • @pro Your actual problem is only described by "EF does not update, it always wants to create a new record." How could anyone tell what's wrong with that kind of information? That's why you get these lengthy discussions. I'm sure that skipping the noise and showing some relevant code would instantly reveal your problem. – Gert Arnold Jul 31 '12 at 22:11
  • @GertArnold: Yeah, you put it this way. I will edit the question. Thanks for your concretion. – bitsmuggler Aug 01 '12 at 08:25

3 Answers3

1

You need to make a decision in your business layer based on characteristics of the entity. If your entity has an ID, then it must be already existing, and therefore you should use

context.YourEntities.Attach(entity);
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);

but if it hasn't, then it's new, and you can use

context.YourEntities.AddObject(entity);

then after both paths,

context.SaveChanges();
podiluska
  • 50,950
  • 7
  • 98
  • 104
  • Hi podiluska, thanks for your answer. I think, that works for the scenario eager loading, but for the lazy loading scenario? I can't attach any entity, because the ID is already in the context. Do you know what I mean? – bitsmuggler Aug 01 '12 at 09:39
  • 1
    @pro then you need `context.YourEntities.ApplyCurrentValues(entity);` – podiluska Aug 01 '12 at 09:46
0

You need to attach the entity :

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);

Have a look at this answer for full details : Entity Framework 4 - AddObject vs Attach

And here is MSDN reference : http://msdn.microsoft.com/en-us/library/bb896271.aspx

For context lifespan details, have a look at this answer : Questions about Entity Framework Context Lifetime

Community
  • 1
  • 1
mathieu
  • 30,974
  • 4
  • 64
  • 90
  • Thanks for the link. You only get the person by the context. But the existing person is in my case a parameter of the method, which comes from the domain layer (which is created from the automapper)... – bitsmuggler Jul 30 '12 at 08:39
  • you can configure Automapper to create your entity using the above method. IE : create it by getting it from EF, then update the properties coming from the VM. – mathieu Jul 30 '12 at 08:40
  • Hi - this is interessting, I doesn't know about this automapper configuration. But in my case the service layer, which does the transformation, doesn't know about the db context... – bitsmuggler Jul 30 '12 at 08:42
  • Then why is it creating db context related objects ? – mathieu Jul 30 '12 at 08:44
  • The created EF entity is not db context related. I can create it without any db context, or is there a misstake? In my opinion the service layer should do this transformation and doesn't know about the or mapper, so I can exchange the layers easily. – bitsmuggler Jul 30 '12 at 09:26
  • Leaking abstraction : your EF layer needs an entity that has specific caracteristics. Creating it in your EF layer will be simplier. – mathieu Jul 30 '12 at 09:31
0

You need to attach the entity, then change the entity state to Modified

Toby Couchman
  • 522
  • 4
  • 14
  • Hi Toby Couchman, thanks for your anwer. But as I said in a comment: "...but in my opinion this doesn't work, because the context are aware of the entity => it will throw an exception (multiple entities with the same id).." – bitsmuggler Jul 30 '12 at 09:24
  • Ok I think I understand - basically, your data access layer can't tell what's been added or modified (or even deleted) from the object graph alone and so it doesn't know what to set the EntityState to? – Toby Couchman Jul 30 '12 at 14:58
  • Yes my dataaccess layer doesn't know about create or update. There is only a save method. – bitsmuggler Aug 01 '12 at 08:28