开发者

'Uncomplete' POCO on client - Can I fill up the collections later?

I have a setup with Client -> WCF -> POCO -> EF4.

Say I have a list with A entities. The A entity contain among other properties a huge list of B entities that isn't loaded by default. When a certain action is done on the client, it may need to know the list of B entities...

If I load the B entities for the A entity and attach them to the collection, the A entity is in effect changed, and I guess when saving the entity it will also save these 'new' B entities to the A entity?

I could wire up a GetEntityWithAllDetails function, but then I would get some data that I already have, and if there were other collections I didn't want to load, it would be a compl开发者_JS百科ete mess.

The question can be boiled down to how can I recomplete the POCO on the client side when I only have a partial POCO to start with and want to avoid loading data twice and still being able to rely on EF4 to save the entity correctly?


That is a complex task and EF doesn't handle it - it is your responsibility. When you use detached entities the change tracking is up to you.

Your solution currently probably is:

  • Client sends request to WCF service
  • WCF uses EF to get data, close context and return POCO graph or partial graph back to client
  • Client modifies the POCO graph / partial graph and sends modified data back to WCF service
  • WCF creates new EF context and saves the POCO graph

Sounds easy but it doesn't. In the last step you must manually explain to the new context what has changed. It generally means heavy interaction with ObjectStateManager (in case of ObjectContext API) or DbChangeTracker (in case of DbContext API). It also means that you must pass information about changes from the client.

For example suppose that you are modifing Order entity. Order entity is dependent on Customer entity and it has dependent OrderItem entities. To make this interesting suppose that OrderItems must be processed by different warehouses so each warehouse has access only items assigned to it.

  • In the step one you will request Order from one warehouse
  • In the step two you will retireve Order without Customer and with a supset of OrderItems.
  • In the step three the warehouse modifies sevaral OrderItems as processed. Deletes single OrderItem because of discontinued product and inserts another OrderItem for replacement of discontinued product. Because of insufficient supplies some items will be unchanged. The warehouse sends Order back to the server.
  • What will you do in the step four? You must apply some knowledge. The first knowledge is that cutomer was not send to client so you can't modify a customer relation. In case of foreign key relation it means that CustomerId can't be modified. Now you must explicitly say which OrderItem was updated (= exists in DB), which was unchanged (= doesn't need any action), which was inserted (= must be inserted) and the worst part which was deleted (if you don't send some information about deletion from the client you can't know it without reloding the entity graph from the database).

At least you can be happy that EF will not delete anything you explicitly don't mark for deletion. So order items related to other warehouses and their relations to the order will be unchanged.

There are two general approaches how to deal with it:

  • Load entity graph first and merge changes into the graph. Then save the attached (loaded) graph. You will simply compare the loaded entity graph with the received entity graph and process all required updates, deletes, inserts.
  • Use self tracking entities instead of POCOs which are implementations of Change set pattern and are able to track changes on the client. STEs have some disadvantages which make them useless in certain scenarios.

There is also completely separate architecture approach using DTOs instead of direct EF POCOs but it results in same complications as you have at the moment.


Welcome to n-tier development.

This sort of situation is exactly why many architected enterprise scale solutions use data transfer objects between tiers.

I would recommend avoiding domain entity propagation from the service (business) tier to the client. If you go down the track of having entities become aware of whether they are fully loaded, or what tier they are currently on, they are hardly "POCO" are they?

So you write a service method "GetEntityWithAllDetails". It should take a GetEntityWithAllDetailsRequest object and return a GetEntityWithAllDetailsResponse object containing whatever the caller of the service expects, and no more.

Obviously there is a far bit of mapping to be done between between DTO's and domain objects - libraries such as Automapper (and others) can help with that.

Propagating domain entities to the client also retricts your flexibiltiy with regards to lazy or eager loading of entities and leaves you having to deal with re-attaching/merging entities, which is problem with EF becuase it will not re-attach entity graphs - you must walk the graph manually.

I will try and say it really plainly. Propagating domain entities from the service to the client is the road to programming hell and very quickly leads to objects having all sorts of responsibilties that are orthoganol to their purpose.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜