I'm lost ...

Posts   
 
    
ChBaeumer
User
Posts: 175
Joined: 23-Oct-2003
# Posted on: 29-Mar-2005 11:15:37   

Hi,

I'm a little bit lost of the following:

DataAccessAdapter, UnitOfWork and the new Context.

I'm moving my application from the 'old' LLBLGen to the new one. With the old LLBLGen I had my own context which bassically inherits from DataAccessAdatper and acts as a factory to create or look up entities.

Within my own context I took care of what entities are newly created, deleted, updated and within the Save-method either all enties were written back or the whole context was rollbacked.

After a successfull save events (defined in the entities) were fired, since we have a distributed scenario, so that all clients could take care of the changes.

With the new version I though I could simplify my implementation and use the above mentioned classes.

Ok, the DataAccessAdapter is resposibly for reading and writing entites. Now comes the LLBLGen context. Where does the data for this class comes from?

The are so many things mixed up (in my opinion):

Reading enties with the adapter and add them to the context. Lookup entites in the context. If the entity is not found this entity is created ind the context. Then add/delete these enties to/from the UnitOfWork since commiting/rollback.

Where is the difference between UnitOfWork and Context?

Then there is a property ActiveContext in the generated enties. Where does this context come from?

Thanx

Christoph

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 29-Mar-2005 12:03:27   

ChBaeumer wrote:

I'm a little bit lost of the following:

DataAccessAdapter, UnitOfWork and the new Context.

I'm moving my application from the 'old' LLBLGen to the new one. With the old LLBLGen I had my own context which bassically inherits from DataAccessAdatper and acts as a factory to create or look up entities.

Within my own context I took care of what entities are newly created, deleted, updated and within the Save-method either all enties were written back or the whole context was rollbacked.

After a successfull save events (defined in the entities) were fired, since we have a distributed scenario, so that all clients could take care of the changes.

With the new version I though I could simplify my implementation and use the above mentioned classes.

No, the Context in LLBLGen Pro is a bit different. It's solely for uniquing, i.e.: offering you a way to get a single entity instance for an entity's data, within a semantic context. So you can have 2 Context objects, both holding a CustomerEntity instance for "CHOPS", and use either one of them to get a unique object instance of "CHOPS". That's also why it's not coupled with an adapter, as it is an object defining a context, which can use multiple adapters. It's not related to a UnitOfWork either, as the UnitOfWork defines work on a set of entities.

Ok, the DataAccessAdapter is resposibly for reading and writing entites. Now comes the LLBLGen context. Where does the data for this class comes from?

From the adapter you use to fetch the data into the Context object. LLBLGen Pro uses a disconnected architecture. This means that there is no 'session' which takes care of everything (you'll see these objects normally in O/R mappers, which also contain a context cache). The disconnected architecture means that I can have a context object which provides unique instances for me IN a context I define for myself, and I use a data-access-adapter to read / write data. This for example means that if I read an entity from SqlServer, using the SqlServer adapter into my Context, and I then read it from Oracle, using the Oracle adapter, I still get one single instance, as the entity is unique in the context I specify.

To get a disconnected 'context', it couldn't be added to an adapter. I first designed it as a database specific object, but that would not work, as I then had to reference the database specific projects at places I didn't want to nor needed to.

So the context is solely for uniquing, getting unique instances. In a lot of cases, you don't need this, or can't even use it (in remoting for example).

The are so many things mixed up (in my opinion):

Reading enties with the adapter and add them to the context. Lookup entites in the context. If the entity is not found this entity is created ind the context. Then add/delete these enties to/from the UnitOfWork since commiting/rollback. Where is the difference between UnitOfWork and Context?

UnitOfWork defines work to be done on the persistence storage. The context defines unique instances of entities. So you can have 1 UnitOfWork and 3 Context instances.

The thing that makes this a bit hard to understand I think is that there is no connected architecture. In the average O/R mapper, you have a 'session' or 'context' object which simply does: executing queries, creating new entities, providing UnitOfWork functionality, offers caching, contains the persistence mapping info, etc.

LLBLGen Pro works disconnected, you work with your classes the way you always do, and use objects with behavior to get things done, like the DataAccessAdapter for persistence, the UnitOfWork to group work along tiers/processes and the Context to create uniquing, for the context represented by that Context instance.

The disconnected behavior has many advantages, for example you can work with a UnitOfWork object along distributed tiers and plug in adapters without problems that they don't know about an entity.

Would I combine them all to one super session object, a lot of these advantages would be gone.

I didn't combine UnitOfWork and Context together because the UnitOfWork is a work grouping object, and the Context is a unique-instance-within-a-semantic-context grouping object, and doesn't care about work being planned for a set of objects. I also didn't combine context with adapter, to avoid having to work with one adapter for a given context, while they don't relate: the adapter is used to fetch data, after that's done, the adapter is disposed, the context however lives on, for example in an ASP.NET session object, and is after the postback again used to fetch data, but in the same unique instances.

Then there is a property ActiveContext in the generated enties. Where does this context come from?

This is set when you add an entity to a context object, so when you add it to another context object it knows the entity instance is already added to a context object.

Difference between entity, entity instance and entity definition I also think the misunderstanding comes from the fact that most people think the instance of the entity class is the entity. It's not, it's an instance of the .NET representation of the entity definition. The data inside the entity instance, that's the entity. To get one copy of that data in memory, in a given semantic context, it is useful to use just one instance of the entity definition with the actual entity data in that semantic context, so 3 entities all referencing the same CustomerEntity "CHOPS" indeed hold all 3 a reference to the same entity definition instance, a CustomerEntity object, with the CHOPS data.

As I said earlier, the Context is an object you'd use if you want uniquing. If you don't need it, and in a lot of situations you don't need it, don't bother with it. Though if you need it, if you need a unique instance of an entity definition which is the only object which holds a given entity's data, within a semantic context, use the Context object to get that functionality.

The Context is also used for fetching child entities into an existing object graph using a prefetch path which is extended from the first fetch. To be able to merge newly fetched objects into existing objects, you've to specify a (not 'the', there can be more simple_smile ) Context in which the existing objects are added to and thus unique. The object fetcher then uses these object instances to represent the read entities and then merges the new child entities into these objects, which thus results in newly fetched entities as child entities in a graph.

Example: you have fetched 10 customers and you now want to fetch their orders. You add the customers to a context, specify that context to the adapter and fetch customers + orders. The orders are then merged into the existing customer instances. If you don't specify the context, the orders are read and merged into NEW customer instances. This wouldn't be a problem, but if you want to re-use the existing customer objects (i.e. the instances), they have to be unique inside a given semantic context, so you use a context object to provide such a semantic context. simple_smile

Perhaps I made things overly complicated, but to me it was the most easiest way to add uniquing to the framework, which is loosely coupled and therefore can't use a central 'know-it-all' object to which the context would be added to.

Frans Bouma | Lead developer LLBLGen Pro
ChBaeumer
User
Posts: 175
Joined: 23-Oct-2003
# Posted on: 29-Mar-2005 12:25:02   

Hi Otis,

hmm, I already figured by myself that your design gives the most flexibility simple_smile And flexibility is always complicated.

I think my (personal) problem here is that I implemented my Context/UnitOfWork/Adapter mixture (our entities within an UnitOfWork have to be unique) and now I thought I could simply switch (more or less) to your code since we need all the stuff like uniqueness (since we have a distributed application with fat clients and the database just as persistence storage) and reading your manuals sounded so promising on these things wink

Now, I guess I will throw away my code anyway and move to your solution

Thanx for your fast response

Christoph

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 29-Mar-2005 13:30:00   

simple_smile If you run into weird things with the implementation, don't hesitate to ask for a change. The code as it is now, is the first design, so it might (likely) have some issues here and there.

Frans Bouma | Lead developer LLBLGen Pro