EntityCollection with DirtyEntities and DeletedEntities

Posts   
1  /  2  /  3
 
    
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 09:41:06   

I can only outline my problem with a senario:

  • a InvoiceEntity has an EntityCollection property InvoiceDetailCollection

  • a BL manager class (InvoiceManager) manages actions on InvoiceEntity and InvoiceDetailEntity.

  • the UI calls InvoiceManager.FetchList(someFilter, somePrefetch) to retreive an EntityCollection of InvoiceEntity with a InvoiceDetailPrefetch

  • the UI deletes some InvoiceDetailEntity objects from the InvoiceDetailCollection property

  • the UI requests to save the current InvoiceEntity object by calling: InvoiceManager.Save(currentInvoiceEntity)

this save operation should only need to delete the InvoiceDetailEntity objects that were deleted from the InvoiceDetailCollection property.

the problem is that the BL has no way of knowing what are the deletedEntities of the InvoiceDetailCollection property because the collection does NOT track any objects deleted from the collection.

solution: why does NOT the entity collection keep a DeletedEntities readonly property that tracks any deleted objects from the collection. The collection can use a flag property (TrackDeletedEntities) that switches on this tracking.

NOTE: DataTable does this by tracking a VERSION (Original, Current) of each DataRow that can be used to know which DataRows were deleted.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 03-Apr-2006 10:58:15   

Removing an entity from a collection doesn't mean it has to be deleted from the db, it can also mean you just want to remove it from the collection because the operation you want to perform doesn't have to access the entity.

If you want to get notified which entities are removed from a collection, bind to the beforeremove event of the entitycollection or do it in the event handler of the control which does the removal (the grid for example). That last one is recommended, as BeforeRemove is refactored in v2.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 11:10:55   

Otis wrote:

Removing an entity from a collection doesn't mean it has to be deleted from the db, it can also mean you just want to remove it from the collection because the operation you want to perform doesn't have to access the entity.

If you want to get notified which entities are removed from a collection, bind to the beforeremove event of the entitycollection or do it in the event handler of the control which does the removal (the grid for example). That last one is recommended, as BeforeRemove is refactored in v2.

Agree that events can trap the entities being deleted from the collection, but this meens that I have to rely on the UI to build an artificial (and external) list of DeletedEntities from the collection. Then the UI must pass thsi list to the BL WITH the parent entity (InvoiceEntity) to save to the DB. The problem with this approach is that it looks so artificial AND it creates a Data coupling between the UI and BL class...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 03-Apr-2006 12:36:43   

True, but for the collection, if an entity is deleted, it's removed from the collection, it doesn't keep state of which entities are removed at which point. If you want to track the WORK you should do, you can build up a UoW at the same time. This is actually what the datatable does too: it records the work that has to be done by the dataadapter.

LLBLGen Pro considers deletes a non-automatic feature which means that you have to do 1 extra step to get stuff deleted: you have to tell the runtime what to delete and at when.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 13:34:58   

Lovely, but my main point of concern is purely architectural and not related to DataAccess. I want to have a stateless BL manager class that manages all CRUD interaction with the DAL entities.

What you are suggesting is for the UI to build the UoW object and pass it to the BL manager class.

Doesn’t this make the UI more intimate with the Data instead of having the BL manage actions and behaviors?

At the end of the day, I want a stateless BL class to manage all the required behavior and utilize Entity objects and EntityCollection objects as data containers. The UoW object is more related to working with Data than working with behavior. This would present the UI with a loophole to circumvent my BL and build actions it want to COMMIT irrespective of the BL’s control (unless I want the BL to inspect the UoW contents and start accepting/rejecting actions which is opening another can of worms IMHO).

If the EntiyCollection tracks its DeletedEntities (when a its TrackDeleted=True), this is still more natural because the UI is still sending a Data object to the BL and not list of actions to execute.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 03-Apr-2006 14:37:53   

omar wrote:

Lovely, but my main point of concern is purely architectural and not related to DataAccess. I want to have a stateless BL manager class that manages all CRUD interaction with the DAL entities.

What you are suggesting is for the UI to build the UoW object and pass it to the BL manager class.

Doesn’t this make the UI more intimate with the Data instead of having the BL manage actions and behaviors?

Not that much I think. The UI IS the interface to the actions to perform, so tracking which actions to perform in a UoW, is IMHO more logical.

In fact, it's more clear. If your UI removes an entity from an entitycollection, NOT to delete it from the DB but to remove it from the entitycollection for some processing, it will be tracked as 'deleted' but it shouldn't be removed from the db! However if your code tracks the actions to perform in the UoW, you won't have that ambiguity.

At the end of the day, I want a stateless BL class to manage all the required behavior and utilize Entity objects and EntityCollection objects as data containers. The UoW object is more related to working with Data than working with behavior. This would present the UI with a loophole to circumvent my BL and build actions it want to COMMIT irrespective of the BL’s control (unless I want the BL to inspect the UoW contents and start accepting/rejecting actions which is opening another can of worms IMHO).

If the EntiyCollection tracks its DeletedEntities (when a its TrackDeleted=True), this is still more natural because the UI is still sending a Data object to the BL and not list of actions to execute.

It then is a de-facto UoW. You then have to inspect the entities in the collection which should be deleted, and delete them manually anyway.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 15:04:46   

Otis wrote:

Not that much I think. The UI IS the interface to the actions to perform, so tracking which actions to perform in a UoW, is IMHO more logical.

In fact, it's more clear. If your UI removes an entity from an entitycollection, NOT to delete it from the DB but to remove it from the entitycollection for some processing, it will be tracked as 'deleted' but it shouldn't be removed from the db! However if your code tracks the actions to perform in the UoW, you won't have that ambiguity.

Ok.. I am soldsmile . One issue remaining. If the UI passes to the BL manager class a UoW object to commit, the BL class needs to attach an instance of the appropriate validation class. This means I need a way to match each entity within the UoW actions to an instance of its validation class. Can that be done with the UoW (once the validation framework is released with LLBL2)?

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 03-Apr-2006 16:25:15   

The following was copied from the "Using the generated code -> Validation per field or per entity" section in the LLBLGen Pro documentation.

Setting IEntityValidator instances at runtime To make life easier, instances of IEntityValidator implementations should be set automatically, so that when you create an instance of an entity, the entity's IEntityValidator instance is set as well, making it impossible to forget to set the validator which could lead to bugs in your application. There are various places to set an entity's IEntityValidator instance. For example, in the user code region in the initializing routines in an entity. You can automate this by generating code into this method using an include template. See for more details about this Adding your own code to the generated classes.

You can also opt for setting the IEntityValidator instance when you add an entity to an entity collection. To achieve that, you should set the entity collection's EntityValidatorToUse property to the IEntityValidator instance which should be set to all entities added to the collection.

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 18:09:44   

Walaa wrote:

You can also opt for setting the IEntityValidator instance when you add an entity to an entity collection. To achieve that, you should set the entity collection's EntityValidatorToUse property to the IEntityValidator instance which should be set to all entities added to the collection.

I was referring to the new Validation architecture in LLBLv2.0. What I want is for the BL to assume responsibilty to hook any entity it gets from the UI with an instance of an appropiate VALIDATOR object. This way I make sure that if a developer has set a validator in the GUI, it is overruled by the new validator as the BL is in charge not the GUI.

What I can't figure out is how to grab an entity or/and entityCollection from a UoW so to assign each entity an instance of its matching Validator class before an adapter commits the UoW.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 03-Apr-2006 18:14:19   

omar wrote:

Walaa wrote:

You can also opt for setting the IEntityValidator instance when you add an entity to an entity collection. To achieve that, you should set the entity collection's EntityValidatorToUse property to the IEntityValidator instance which should be set to all entities added to the collection.

I was referring to the new Validation architecture in LLBLv2.0. What I want is for the BL to assume responsibilty to hook any entity it gets from the UI with an instance of an appropiate VALIDATOR object. This way I make sure that if a developer has set a validator in the GUI, it is overruled by the new validator as the BL is in charge not the GUI.

What I can't figure out is how to grab an entity or/and entityCollection from a UoW so to assign each entity an instance of its matching Validator class before an adapter commits the UoW.

Use the GetEntityElementsTo... and GetEntityCollectionElementsTo... methods on the UoW to get the elements scheduled internally in the UoW.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 21:36:33   

Otis wrote:

omar wrote:

Lovely, but my main point of concern is purely architectural and not related to DataAccess. I want to have a stateless BL manager class that manages all CRUD interaction with the DAL entities.

What you are suggesting is for the UI to build the UoW object and pass it to the BL manager class.

Doesn’t this make the UI more intimate with the Data instead of having the BL manage actions and behaviors?

Not that much I think. The UI IS the interface to the actions to perform, so tracking which actions to perform in a UoW, is IMHO more logical.

In fact, it's more clear. If your UI removes an entity from an entitycollection, NOT to delete it from the DB but to remove it from the entitycollection for some processing, it will be tracked as 'deleted' but it shouldn't be removed from the db! However if your code tracks the actions to perform in the UoW, you won't have that ambiguity.

I'm sorry, but this issue is still bugging me.

If the UI is to build UoW objects with actions and sends those to the BL to execute, then BL's role is cut down to just executing UoW objects build by the UI.

This is very reminiscent to writing inline SQL in the UI to perform CRUD operations directly against the DB.

For example, If the BL’s InvoiceManager has a PostInvoice method that involves the entities InvoiceEntity, InvoiceDetail, GLEntity, TransactionEntity; and does it work by creating/updating entries in these entities.

If the UI can build a UoW object to save an invoiceEntity and create an entry in GLEntity (not involving TransactionEntity) and then send that UoW to the BL to execute. This is clearly by-passing the BL and directly executing actions against the DB layer.

I want to think of my BL classes as being defined by behavior not by data (unlike the entity classes) and the UI calls onto those BL classes to execute the actions it needs.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 03-Apr-2006 22:15:28   

You can also opt for queueing the entities to delete (which is thus something else than removed entities from a collection) into 1 entity collection and pass that to the BL for deletion.

It's the ambiguity that Remove() and RemoveAt() have that makes the entitycollection you're removing from not a good candidate for tracking deletions.

With the entitycollection with entities to delete, (and I think the gui knows when an entity has to be deleted), you don't record actions in a UoW, but still have the flexibility of having the difference between Remove() to remove an entity from a collection and actually deleting the entity from the db. Would that work?

Another option is a facade tier on top of the BL, which takes care of pre-processing of data from gui to BL and makes sure the BL gets the data it needs.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 03-Apr-2006 22:49:06   

Otis wrote:

You can also opt for queueing the entities to delete (which is thus something else than removed entities from a collection) into 1 entity collection and pass that to the BL for deletion.

It's the ambiguity that Remove() and RemoveAt() have that makes the entitycollection you're removing from not a good candidate for tracking deletions.

With the entitycollection with entities to delete, (and I think the gui knows when an entity has to be deleted), you don't record actions in a UoW, but still have the flexibility of having the difference between Remove() to remove an entity from a collection and actually deleting the entity from the db. Would that work?

I did consider having the UI build a collection to house child-entities (that need to be deleted from the DB when saving a parent entity) but I was not comfortable with the idea of having a BL's class SAVE method that accepts a parameter a collection of entities to delete from the DB. But I think you'r right when you say that the UI KNOWS when an entity has to be deleted and I also guess this is a comprmise I have accept for having a stateless BL layer. (Still, it would've been nice to encapculate the whole issue in the EntityCollection itself although I see that you worry about the confusion this could raise among developers).

Otis wrote:

Another option is a facade tier on top of the BL, which takes care of pre-processing of data from gui to BL and makes sure the BL gets the data it needs.

Can you elaborate how does this FACADE layer communicate with both the BL and UI layers??

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 04-Apr-2006 10:00:07   

omar wrote:

Otis wrote:

You can also opt for queueing the entities to delete (which is thus something else than removed entities from a collection) into 1 entity collection and pass that to the BL for deletion.

It's the ambiguity that Remove() and RemoveAt() have that makes the entitycollection you're removing from not a good candidate for tracking deletions.

With the entitycollection with entities to delete, (and I think the gui knows when an entity has to be deleted), you don't record actions in a UoW, but still have the flexibility of having the difference between Remove() to remove an entity from a collection and actually deleting the entity from the db. Would that work?

I did consider having the UI build a collection to house child-entities (that need to be deleted from the DB when saving a parent entity) but I was not comfortable with the idea of having a BL's class SAVE method that accepts a parameter a collection of entities to delete from the DB. But I think you'r right when you say that the UI KNOWS when an entity has to be deleted and I also guess this is a comprmise I have accept for having a stateless BL layer. (Still, it would've been nice to encapculate the whole issue in the EntityCollection itself although I see that you worry about the confusion this could raise among developers).

Otis wrote:

Another option is a facade tier on top of the BL, which takes care of pre-processing of data from gui to BL and makes sure the BL gets the data it needs.

Can you elaborate how does this FACADE layer communicate with both the BL and UI layers??

I combined my reply to the two parts of your message into one answer as I think it's related simple_smile .

Typically, you have a UI which forms the interface to the functionality of the application. It's consuming various entities and relies on multiple parts of the BL, per screen: an order entry screen not only shows orders but also customer and perhaps other information.

If you look at it closely, the UI in fact records actions and plays them back on the application state using the BL logic. Example of this is a user deleting 2 orders of a customer, altering one and adding a new one. That's 4 actions, recorded by the UI and played back on the BL when the user hits OK or Save. (Not necessarily on OK, but you get the point).

I exxagerated it a bit, to illustrate what I wanted to say but if you take a step back, you in fact want to translate those actions recorded in the GUI to BL calls. This translation is done by a BL facade tier. In that tier, which lives between GUI and BL, you translate actions from the GUI into calls to the BL. So it doesn't contain any logic per se, it just makes sure the right code is called in the BL. This gives a lot of freedom: you can develop your BL as you see fit and your GUI isn't tied to a BL structure.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 05-Apr-2006 10:31:51   

FRANS.. I am sorry for nagging you with this issue but I am begging your patience disappointed

Otis wrote:

You can also opt for queueing the entities to delete (which is thus something else than removed entities from a collection) into 1 entity collection and pass that to the BL for deletion.

It's the ambiguity that Remove() and RemoveAt() have that makes the entitycollection you're removing from not a good candidate for tracking deletions.

With the entitycollection with entities to delete, (and I think the gui knows when an entity has to be deleted), you don't record actions in a UoW, but still have the flexibility of having the difference between Remove() to remove an entity from a collection and actually deleting the entity from the db. Would that work?

Why would you say that keeping the DeleteEntities is ambiguous? It is just accommodating the developer's request (that he made by sitting the collection's flag TrackDeletedEntities=True) by adding any removed entity from the collection to the DeletedEntites property?

This has no message that this deletedEntities would be deleted from the DB. As a data container, the collection now is keeping track of ALL changes to its data:

  • Inserted and Updated are known by the flags of the contained entities
  • DeletedEntities are known by consulting the DeletedEntities property

This way, the collection consumer has a full BEFORE/AFTER image of the data in the collection.

For me, the entityCollection is not just a collection data-structure BUT it is data container, just like a DataTable is not just a collection of row objects BUT rather a data-container that DOES keep track of the BEFORE/AFTER image of all data changes to the row objects it contains.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 05-Apr-2006 11:27:38   

omar wrote:

FRANS.. I am sorry for nagging you with this issue but I am begging your patience disappointed

Otis wrote:

You can also opt for queueing the entities to delete (which is thus something else than removed entities from a collection) into 1 entity collection and pass that to the BL for deletion.

It's the ambiguity that Remove() and RemoveAt() have that makes the entitycollection you're removing from not a good candidate for tracking deletions.

With the entitycollection with entities to delete, (and I think the gui knows when an entity has to be deleted), you don't record actions in a UoW, but still have the flexibility of having the difference between Remove() to remove an entity from a collection and actually deleting the entity from the db. Would that work?

Why would you say that keeping the DeleteEntities is ambiguous? It is just accommodating the developer's request (that he made by sitting the collection's flag TrackDeletedEntities=True) by adding any removed entity from the collection to the DeletedEntites property?

myCustomers.TrackDeletedEntities = true; // lots of code, calls to other routines // ....

// in a routine to which you pass myCustomers, this is done: myCustomers.Remove(aGivenCustomer);

now, what does Remove mean here? I dont know, other than that it removes aGivenCustomer from the collection myCustomers. Should it be removed from the DB? Unclear, the setting for that is done elsewhere.

It's this kind of obscurity I want to avoid. simple_smile

This has no message that this deletedEntities would be deleted from the DB. As a data container, the collection now is keeping track of ALL changes to its data:

  • Inserted and Updated are known by the flags of the contained entities
  • DeletedEntities are known by consulting the DeletedEntities property

This way, the collection consumer has a full BEFORE/AFTER image of the data in the collection.

Now, what should be done with entities removed from a collection? Should they still stick around inside the collection? If so, why ??

Also, the collection doesn't track changed entities, the entities do. The collection is just passed in as a bucket of entities to save for example. though It's faster to simply pass the entities which are changed in another collection and save that collection. this is because only the ones in the collection have to be examined, while otherwise every entity is sorted and if you have 1000 entities and 2 are changed, this leads to a lot of overhead for nothing.

For me, the entityCollection is not just a collection data-structure BUT it is data container, just like a DataTable is not just a collection of row objects BUT rather a data-container that DOES keep track of the BEFORE/AFTER image of all data changes to the row objects it contains.

However the sole reason you want this is for persistence. So let's not make things more obscure: you're arguing this should be added because you then can pass the collection to a routine and which entities to delete is easy to check, correct? Why else track the deleted entities INSIDE a collection they no longer belong to? So I then say: there's already a way to do it (two actually, I described them above, with a 3rd one, more abstract with the commands as well)

Now, adding this would add another way of specifying which objects to do actions on, besides the UoW.

Also, if I remove aGivenEntity from myCustomers, for me aGivenEntity isn't present in nor part of myCustomers, however I need myCustomers to get it deleted! Which is IMHO odd, because I removed it from that collection in the first place.

I won't add another way of tracking what to do to the framework, for the reasons I've given before. I'm sorry, but I can't add support for everyone's way of working with data. I've tried hard to make things as clear as possible so no obscurity or 'hidden things'. If you want the framework to do things for you, tell it to do those things, which IMHO is more clear and thus less error prone than setting some flag somewhere and everything gets done below the surface. That could work in some situations but if routine A gets a collection passed in and delete tracking is switched on to that collection by caller 1 and switched off by caller 2, the developer working on A has no clue what will happen if he calls Remove on the passed in collection in A.

Frans Bouma | Lead developer LLBLGen Pro
omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 05-Apr-2006 11:59:22   

Thnak you for your repsonse. I will try to adapt to the LLBL rules as you stated.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 05-Apr-2006 12:28:31   

omar wrote:

Thnak you for your repsonse. I will try to adapt to the LLBL rules as you stated.

I think it would be interesting for you (IMHO, but I don't know your app in full of course wink ) to check the command pattern and the facade tier idea I talked about. That might offer you a way to define what should happen after a given ui action in rules which could make your app easier to maintain.

Frans Bouma | Lead developer LLBLGen Pro
Answer
User
Posts: 363
Joined: 28-Jun-2004
# Posted on: 05-Apr-2006 17:36:30   

Frans,

You dont have an example of what you are talking about do you (command/tier)??

Im struggling with the same sitaution....

Currently i have a seperate collection to hold entities that need deletion. But this doesnt seem right...

Using Omars example would you then create a seperate method in the BL to delete InvoiceDetailItem??

So basically you would have

SaveInvoice(InvoiceEntity) - which would save the invoice, and any new or updated invoicedetail items.

DeleteInvoice(int Id) - which woud delete an invoice along with all its detailitems. DeleteInvoiceDetailItem(int id) - which would delete a detailitem.

so essentially, your UI would work make two calls to the BL to save an invoice??

Answer
User
Posts: 363
Joined: 28-Jun-2004
# Posted on: 05-Apr-2006 23:05:44   

The UoW seems almost useless in the UI to me in an N-Tier scenario where all your business logic is placed in one tier.

To me, a simple isDeleted flag on each entity makes much more sense. However, for databinding you would have to provide a way of filtering out deleted entities on a collection.

Then again, maybe im just confused and need to be enlightened smile

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 06-Apr-2006 08:24:16   

I think I've read a post where Frans said he will be having the "isDeleted" flag in his Todo list.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 06-Apr-2006 10:21:18   

Walaa wrote:

I think I've read a post where Frans said he will be having the "isDeleted" flag in his Todo list.

That was some time ago. Implementing it would make things ambiguous again and the 'you can do things in multiple ways'-syndrome was popping his ugly head again too, so I dropped it.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 06-Apr-2006 10:37:00   

Answer wrote:

The UoW seems almost useless in the UI to me in an N-Tier scenario where all your business logic is placed in one tier.

I don't think it's useless. You can use it as a recording device for things to do. People seem to be focussed on 'add as much abstraction as possible' sometimes, it seems. It doesn't hurt to be pragmatic here and there wink .

Nevertheless, I understand that in some scenario's the UoW is indeed not what you need. However, make no mistake: what you will use instead will mimic a UoW object: the user performs actions in the UI which lead to actions to be executed by other logic. You then have a list of 'commands' and 'data' related to these commands, and an order in which the commands have to take place, that's what a UI does. After the UI validation succeeds, you will end up with that kind of data.

You then have to tunnel the commands and their accompanying data objects to the BL or whatever you want to call it, to get them executed.

Most of the time, people don't have time for this and simply tie an eventhandler in a GUI part to a set of calls to the BL, effectively making the translation between commands+data into calls to BL+data.

However, you can also collect the commands+ data in a structure and send it to a command dispatcher in a BL facade tier. There, it translates it to BL calls, does pre-processing of the data and translates the commands+data into objects which can be consumed by the BL.

It can be complex too, but so are other solutions. And don't make the mistake that tracking deletes in a collection is something else than using a UoW, it's not. It's exactly the same thing, only more obscure.

Also, a UoW doesn't have to be executed in the BL. After all, the UI doesn't have an adapter at hand. That's why Adapter is created (among other reasons)-> it offers you the ability to have a UI without any persistence logic. You can use the UoW to collect your work and send it across a remoting connection if you want. On the server or in the BL, you're then consuming the work to be done and proceed, there's nothing weird about that nor is it any different than keeping secret trackings in a collection.

You can for example opt for a facade which accepts a UoW and pre-processes it for the BL which refuses to work with a UoW but works with collections or entities. that's up to you. What you have to do is that you collect the work to be done.

It's just that there's a difference between changing an entity's data and save it and deleting an entity. Changing data on an entity is modifying an entity, while deleting an entity is an action, which accepts an entity as a parameter (semantically speaking). A delete action isn't a 'change', and it also requires tight control over when a delete has to take place, despite the hypes around cascading deletes which seem to pop up once in a while that it IS possible in all situations..

To me, a simple isDeleted flag on each entity makes much more sense. However, for databinding you would have to provide a way of filtering out deleted entities on a collection. Then again, maybe im just confused and need to be enlightened smile

'IsDeleted' IMHO doesn't make sense, as it's not really deleted. It's confusing actually. If you want to get rid of an entity, get rid of it. It's the same as with soft-deletes (not really deletes, deleted rows have a flag called 'isdeleted' set to true in the db): it seems to work for a while but then you hit a wall and realize what you're doing isn't useful, for example because your db is overloaded (when the # of 'deleted' objects is getting really big))

Frans Bouma | Lead developer LLBLGen Pro
Answer
User
Posts: 363
Joined: 28-Jun-2004
# Posted on: 06-Apr-2006 17:51:35   

After thinking about this issue last night and reading your post, i agree that an isdeleted flag is probably not the best thing. Now, in my app if could just tie a GUI event handler to a business logic call, that would make my life so much easier simple_smile

Unfortantually i cannot do this, and i have the scenario where user changes data, and then clicks save where all changes are then sent over the wire to my Manager classes using .NET remoting.

The unitofwork class is basically exactly what i want, however, here is where im hitting the wall. And in reality i would have the same problem if i was passing an entitycollection, but like for instance, if im saving a product, i want to auto generate a unique SKU. Now, i could create my manager class so that, each action is a seperate call. So to add a product to a category is another call etc...Noow i have A LOT of these (all on the same GUI screen), so there will be many calls to the Manager class over the wire once the user clicks save which is something that i do not want, however my manager classes are nice and self defining.

The other downside to these seperate calls is that if i understand remoting correctly, passing the productEntity to the saveproduct method transfer not only the productEntity but every other entity that is referenced by it?? so im transfer a LOT of wasted data for each call.

Hence the unitofwork solves all of this, but it makes the Manager classes not so nice. infact, if i pass a saveproduct(UnitOfWork2 productWork), i have to try and inspect this unitofwork and get the productentityout of it, then assign it its SKU etc..I guess that isnt really all that hard, it just seems then, that my manager classes wont have a good definition of what they are doing....infact, it seems like i almost dont even need the manager class anymore...

I suppose you could make typed wrappers around the UnitOfWOrk2 so that only certain objects could be added to, or deleted. But then it becomes more of a BusinessObject??

omar avatar
omar
User
Posts: 569
Joined: 15-Oct-2004
# Posted on: 07-Apr-2006 10:13:38   

Answer wrote:

After thinking about this issue last night and reading your post, i agree that an isdeleted flag is probably not the best thing. Now, in my app if could just tie a GUI event handler to a business logic call, that would make my life so much easier simple_smile

Unfortantually i cannot do this, and i have the scenario where user changes data, and then clicks save where all changes are then sent over the wire to my Manager classes using .NET remoting.

The unitofwork class is basically exactly what i want, however, here is where im hitting the wall. And in reality i would have the same problem if i was passing an entitycollection, but like for instance, if im saving a product, i want to auto generate a unique SKU. Now, i could create my manager class so that, each action is a seperate call. So to add a product to a category is another call etc...Noow i have A LOT of these (all on the same GUI screen), so there will be many calls to the Manager class over the wire once the user clicks save which is something that i do not want, however my manager classes are nice and self defining.

The other downside to these seperate calls is that if i understand remoting correctly, passing the productEntity to the saveproduct method transfer not only the productEntity but every other entity that is referenced by it?? so im transfer a LOT of wasted data for each call.

Hence the unitofwork solves all of this, but it makes the Manager classes not so nice. infact, if i pass a saveproduct(UnitOfWork2 productWork), i have to try and inspect this unitofwork and get the productentityout of it, then assign it its SKU etc..I guess that isnt really all that hard, it just seems then, that my manager classes wont have a good definition of what they are doing....infact, it seems like i almost dont even need the manager class anymore...

I suppose you could make typed wrappers around the UnitOfWOrk2 so that only certain objects could be added to, or deleted. But then it becomes more of a BusinessObject??

These are the same daemons that I am struggling with. As FRANS said, UoW action recording functionality is exactly what we need in this scenario BUT to keep our class’s focused on what they are doing, we need (for the lack of better term) a “strongly typed UoW” object. The UoW object send from the UI to the BL’s manager class should only accept InvoiceDetail (with delete action). If a BL class accepts a UoW from the UI and executes it blindly then the BL boils down to nothing more than an adapter-factory and executer layer. I do agree with FRANS that my proposed solution of tracking DeletedEntities is NOT the right way to go, I just wish there was a CLEAN way to do this without breaking OOD guidelines, but maybe we do need to be more pragmatic confused

1  /  2  /  3