Example of using EF 4 (DBContext) with Catel model classes

Topics: Questions
Jun 16, 2012 at 10:48 AM

Does anyone have an example (of some guidance) on how to combine a model consisting of Catel DataObjectBase classes and the Entity Framework 4 (using DBContext and POCO)?

I can't seem to grasp how to do this :(

I have defined a EF model with some classes. I use DBContext generator to generate POCO classes.

I also have defined model classes which inherit from Catel's DataObjectBase. I can't combine them (using partial keyword) because then there would be duplicate properties.

I also don't want to convert every poco object to a Catel model object evert time I query or store the model. You would have to create the entire object hierarchy again!

And besides that I'm using a Repository Pattern in which you can add the where clause as a parameter (using LINQ expressions). If I were to separate the POCO from the Catel version I would have to supply LINQ expressions for the POCO object whilst a Catel object would be returned. This seems wrong too.

Can anyone give some guidance here?

Regards,
Peter


Coordinator
Jun 18, 2012 at 8:20 AM

Isn't it code-first that you should use for custom base classes?

Jun 18, 2012 at 10:43 AM

No, you don't necessarily have to use code-first. But if you provide your own POCO classes, you shouldn't generate them also with DBContext generator :)

So after throwing away those classes, I can use the Catel model classes as POCO object within EF.

Want you should keep in mind is that you have to add the navigation properties to the model classes. And also make the properties virtual if you want to use proxies and change tracking.

So now it basically works over here. I now have to figure out how I can copy the contents of one model object into another.

Does Catel have any helpers for that to? What I mean is the following scenario:

-When displaying a, for example, Customer you retrieve the customer via EF => this will become the model instance

-When saving the changes you would
-create a UnitOfWork in which you retrieve the customer
-modify the customer according to the changes of the user (e.g. according to the model instance)
-commit the UnitOfWork to save changes

It would be nice if I could copy the contents of the changed model instance over the one which has been retrieved in the database without have to do a property assignment of each property.

 

Coordinator
Jun 18, 2012 at 10:56 AM

Copying properties from a model to another model isn't as simple as you might think. You have to consider the whole object graph. For example, if you have a person, what about its children? You cannot just copy the collection (reference), you have to duplicate the whole child collection, and its child collections, and then you have a complete graph to serialize.

This can all be done (although Catel has issues with serializing same references over and over again, we will fix this in 3.3), but you should really consider the performance here.

Why don't you just use the same custom class to save the changes?

Jun 18, 2012 at 11:29 AM

You want the lifespan of the UnitOfWork to be as short as possible. So you can't leave it open the entire time that your edit window is active.

You could retrieve the customer object during load, then re-attach it to the context again when saving, but then you don't have change tracking either and would have to check collections properties manually anyway.

My intentions are to only use this method of saving of master data objects where no collection properties are modified.

I don't know EF well enough yet to be able to solve this issue in a nice manner.

Coordinator
Jun 18, 2012 at 8:33 PM

Only the save action should be included in the UnitOfWork. At least, that's how I implement db stuff. You either commit the changes in the unit of work (when the user clicks OK) or you dismiss the changes and retrieve the object again (depending on what you prefer).

What we can investigate is if we can create a helper that is able to duplicate the DataObjectBase:

1) Just the object itself => collection references will be kept

2) The complete object

 

Internally, we already support this via the BeginEdit and EndEdit (we create full copies in memory), so it should be possible to implement this. However, this will not be included in the 3.2 release (which we are currently trying to finalize).

Jun 18, 2012 at 9:13 PM
Edited Jun 18, 2012 at 9:14 PM

With EF the UnitOfWork is the ObjectContext so everything from creating the context to committing (or not) is included and therefore also reading the entity.

I have asked around and it seems that you can have the context open during the lifetime of an edit window, because locks are only placed when you commit data.

So I solved this as you suggested earlier:
-Create the UnitOfWork
-Read the model
-Create the ViewModel and inject the model
-Open the dialog
-When dialog is closed with OK/Save commit the UnitOfWork
-Dispose UnitOfWork

This seems to work rather well :)

Thanks for the response!

Coordinator
Jun 18, 2012 at 9:14 PM

Yes, only in SaveChanges it actually opens the connection => commits => closes the connection.

Very nice to hear, I think we have another chapter for the docs :)

Jun 18, 2012 at 10:38 PM

This workflow is ok for cases where the UI and the data access are in the same tier/process. 

However in a distributed application (e.g. data access is behind a WCF service interface it is not a good idea to keep the data access UnitOfWork open. In that case you can e.g. use RIA services to do change tracking on the client and send changes to the backend service and let is take care of the database updates. 

Jun 19, 2012 at 11:58 AM

@Geert: I definitely think that this kind of stuff, including usage of EF (or nHibernate if you prefer) would be nice to have in the docs ;)

@ GEERTD: Indeed I didn't mention the scope of the application. In this case it's about a WPF application without WCF services. In distributed applications I agree with you that the lifespan of the UnitOfWork should be as short as possible. Would be nice if you can provide some more info (links to articles?) on how to use change tracking in EF 4 when using WCF(RIA) services.

Jun 20, 2012 at 8:15 AM

There is a project: Value Injecter (http://valueinjecter.codeplex.com/)

I have a plan to use it in my site but haven't tried it.

So I don't know whether it works well between DataObjectBase and EF entity or not.

Jun 27, 2012 at 8:27 AM
Edited Jun 27, 2012 at 8:27 AM
GeertvanHorrik wrote:

Very nice to hear, I think we have another chapter for the docs :)


No need for a chapter in the docs I'm afraid.

Stumbled upon the circular reference issue yesterday.

So I have to revert back to not using DataObjectBase for my domain classes. Hope this doesn't break any other Catel functionality I had out of the box.

Not funny because I changed all my domain classes to use the DataObjectBase (and it's property setters/getters) and now have to changed them back again. I really started to like Catel's auto implementation of the notifychanged and errorinfo interfaces. And also the [Model] and [Expose] attributes. I guess I have to write my own base class again to use attribute based validation on my domain classes.

A real bummer :(

Coordinator
Jun 27, 2012 at 8:28 AM

We are aware of this and a fix is planned in 3.3.

Coordinator
Jun 27, 2012 at 8:35 AM

If a property is non-data object base property, does the issue still occur? Try mapping it around with a XmlIgnore element (the navigation proprties).

Jun 27, 2012 at 8:39 AM
GeertvanHorrik wrote:

We are aware of this and a fix is planned in 3.3.


That is very good to hear, Geert!

Of course this doesn't help me now, because I get a Stack Overflow exception in the (de)serialization so I have to deal with the problem in the current Catel release.

But nice that future developers won't have this same problem!

Jun 27, 2012 at 8:40 AM
GeertvanHorrik wrote:

If a property is non-data object base property, does the issue still occur? Try mapping it around with a XmlIgnore element (the navigation proprties).


Didn't know this feature. Will try it out tonight!

Jun 27, 2012 at 3:25 PM
GeertvanHorrik wrote:

If a property is non-data object base property, does the issue still occur? Try mapping it around with a XmlIgnore element (the navigation proprties).


Alas, using the XmlIgnore attribute on the navigation properties doesn't seem to have any effect. The recursion in Catel.Data.DataObjectBase.CallOnDeserializationCallback(object obj) and Catel.Data.DataObjectBase.OnDeserialization(object sender) still causes a stack overflow exception :(

Jun 27, 2012 at 7:08 PM

Can the (de)serialisation be disabled altogether somehow? Then I can at least continue with the project (without removing Catel from the Domain classes) until 3.3 will be released.

Coordinator
Jun 27, 2012 at 10:15 PM

Issue is solved, it is included in Catel 3.2 RC 2.

Jun 30, 2012 at 1:12 PM

Tested with the new Catel release and the issue is solved. Thanks!

Jul 3, 2012 at 12:57 PM
Dromer1967 wrote:

Does anyone have an example (or some guidance) ...



I still have trouble to understand how to combine model with Database and an ORM-mapper. An example would be very helpful, like e.g. the PersonApplication from the Catel examples extended with Database access.

Kind regards
Nicolo

Coordinator
Jul 4, 2012 at 7:07 PM

In the near future, we don't have time to update the examples. However, it does not differ from any other solution that uses ORM mappers so you can just approach Catel the same way.

If you have any questions, feel free to ask.