Automatic MarkOld

Automatic MarkOld

Old forum URL: forums.lhotka.net/forums/t/1422.aspx


xal posted on Monday, October 09, 2006

Hey everyone, I've gotten into a simple problem.
In 1.x days, you would normally call MarkOld() in your dp_Fetch method, but in 2.x, this is done automatically by the dp.
The thing is that MarkOld() is being called after the fetch operation has occured, so when you have to run your validation rules inside fetch and they behave differently when the object is new and when the object is old, you've got a problem. This is easily solved by calling MarkOld inside your fetch method right before calling CheckRules, but perhaps it would be best to have the dp call MarkOld and then Dataportal_Fetch().
What do you think?

Andrés

JoeFallon1 replied on Monday, October 09, 2006

I agree 100% - I saw this early on in the testing of CSLA 2.0 but figured I was the only one doing rule checking based on the State of the BO (IsNew) so I didn't bother to bring this issue to Rocky's attention.

After my templates Fetch the data I call MarkOld and then call ValidationRules.CheckRules. As noted, one of the rules depends on if the object IsNew or Not.

I like the idea of moving the framework call of MarkOld to just *before* DataPortal_Fetch as it allows me to remove the duplicate call from my templates.

Joe

 

 

RockfordLhotka replied on Monday, October 09, 2006

I've added this to my to-be-considered-for-the-future list.

William replied on Tuesday, October 10, 2006

I think MarkOld() should not be called before DataPortal_Fetch(). In DataPortal_Fetch(), after fetching data for the current object, it might need to invoke the appropriate Fetch() method on child collections or objects. What if the validation rules in these child objects behave differently depending on the IsNew property of the parent?

Regards,
William

RockfordLhotka replied on Tuesday, October 10, 2006

That is a valid concern. However, I think you could argue that the child objects loaded during a Fetch operation should view their parent as being "old".

So perhaps the current model is actually broken in this regard, because a child would (today) find that its parent is "new", when the reality is that the parent is "old" - or will be once the DataPortal_Fetch() method completes.

ajj3085 replied on Tuesday, October 10, 2006

I think the before or after debate is going to be a tricky one to nail down.  I'm sure there are just as many reasons to keep the implemenation the way it is as there are to change it.

I know that a MarkOld before DP_F would break all of my code, because I typically set data via the properties, not directly into the fields. 

RockfordLhotka replied on Tuesday, October 10, 2006

This is because your validation/authorization rules are sensitive to IsNew?

ajj3085 replied on Tuesday, October 10, 2006

No, just a convention I've been using.  IsDirty would be wrong in my case though if MarkOld was made first, unless I go back and change all my code..  I would think there could be other reasons as well, like those that want new objects to be clean, depending on how it was implemented.

RockfordLhotka replied on Tuesday, October 10, 2006

Ahh, yes, the IsDirty issue. There's no doubt that IsDirty would need to be set after the DP_F call. That is a very good point.
 
I was so focused on IsNew that I'd rather lost sight of IsDirty :(
 
So for this to work, I might need to expose more granular methods for the data portal so IsNew can be set to false before DP_F, and IsDirty can be set to false after DP_F.
 
Rocky

No, just a convention I've been using.  IsDirty would be wrong in my case though if MarkOld was made first, unless I go back and change all my code..  I would think there could be other reasons as well, like those that want new objects to be clean, depending on how it was implemented.

JoeFallon1 replied on Tuesday, October 10, 2006

ajj3085:
I typically set data via the properties, not directly into the fields. 

But that is in direct contradiction to Rocky's recommended best practices.

How dare you! <g>

Joe

 

guyroch replied on Tuesday, October 10, 2006

I completly agree with Andrés's original post in that I too was used to calling the MarkOld after a fetch.

In fact I'll go as far as saying that _WE_LOST_ this behavior when we went from CSLA 1.x to 2.0.  At least in 1.x we had the flexibility of calling MarkOld or not.  In 2.0 we have no choice, unless of course we modify the framework - but this warrants its own threaded discussion.

guyroch replied on Tuesday, October 10, 2006

Hey Andrés, on second thought.... it does not make that much sense to call the MarkOld _before_ the dp_Fetch call because your data has not been feteched yet, so how can it be _old_ , or not dirty.

Why not just call the MarkClean() in your dp_fetch.

xal replied on Wednesday, October 11, 2006

Hey guyroch! How was your csla vacation? Smile [:)]
I don't think that's the problem, whether the data has been fetched or not is unimportant. What matters is that you're trying to retrieve data from the db, so the object is "obviously"** going to be old.

The fact that some people (hey Andy!) use the property setters to load the objects doesn't change the fact that you currently don't have much flexibility. In this scenario, you could easily just call mark clean, which is very easy if you use code generation.

I realize it might be a pain for people that depend on that call being made after their code runs, but I don't believe it's a problem for the majority of users. (just a wild guess)

** The current implementation has another problem too. Some people (I haven't had the need to do this yet, but it's something some people might want) make the fetch NOT fail if there's no data on the db, and just return a "new" object with that id if it does not exist.
Now, in that scenario, you'd normally want to call MarkNew in the fetch, but it won't do much good because the dp will mark it as old later. So, in any case, I think this things should be called before DataPortal_Fetch, so that we get more flexibility.


Andrés

ajj3085 replied on Wednesday, October 11, 2006

xal:
I don't think that's the problem, whether the data has been fetched or not is unimportant. What matters is that you're trying to retrieve data from the db, so the object is "obviously"** going to be old.


Hmm... I'm not too sure about that.  Some people have a Get actually return a New object if the data that was requested doesn't exist in the db. 

xal:
The fact that some people (hey Andy!) use the property setters to load the objects doesn't change the fact that you currently don't have much flexibility. In this scenario, you could easily just call mark clean, which is very easy if you use code generation.


How does calling MarkOld before or after the DP_F change the flexiblity?  That is what you are referring to, correct?  It looks to me that either way its implemented it just as inflexible.  Oh, and not all of use code gen.  Wink [;)]

xal:
I realize it might be a pain for people that depend on that call being made after their code runs, but I don't believe it's a problem for the majority of users. (just a wild guess)


The number of people that depend on it being called before or after is probably not a majority.  That's what I'm trying to wrap my head around.. what's the benefit to changing?  It seems that it would benefit one minority over another, with little to no benefit for the majority.

xal:
** The current implementation has another problem too. Some people (I haven't had the need to do this yet, but it's something some people might want) make the fetch NOT fail if there's no data on the db, and just return a "new" object with that id if it does not exist.
Now, in that scenario, you'd normally want to call MarkNew in the fetch, but it won't do much good because the dp will mark it as old later. So, in any case, I think this things should be called before DataPortal_Fetch, so that we get more flexibility.


Well, how about this suggestion, which will give everyone the flexibility they want.

Change the DP so that it never calls MarkOld or MarkNew.  Add a parameter to the DataPortalEventArgs so that the hooks can determine which DP method was called (Create, Fetch, etc.).  Then in your BusinesBase subclass, you can override the Invoke and InvokeCompleted methods, check which method is about to fire / did fire, and call MarkOld / MarkNew, which ever best suits your general needs.

Also, MarkOld / MarkNew are overridable; perhaps that's an alternate route we can take?

Thoughs?
Andy

xal replied on Wednesday, October 11, 2006

Well, again, it is currently inflexible as in you normally would call MarkOld() in the fetch, so it's cool that it's done automatically, but if you need something different like IsNew = True when the object doesn't exist in the db, you can't do it because it will be overriden by the dp.
The flexibility comes in that whatever you do inside Fetch() sticks. Right now, it doesn't matter if you call MarkNew, MarkDirty or whatever, it will all be disregarded because of the MarkOld call done in the dp.

About overriding InvokeCompleted, it would be a pain, because you don't have an easy way of knowing whether the object was retrieved or not from the db unless you set some var indicating that it was loaded or it is new. Inside fetch, you could easily do if (dr.Read()) { ... } else { MarkNew(); }.

That is very straight forward, and doesn't require overriding an "outside method" that doesn't know much about what happened during the fetch (unless you explicitly store that info somewhere).



Andrés

ajj3085 replied on Wednesday, October 11, 2006

xal:
Well, again, it is currently inflexible as in you normally would call MarkOld() in the fetch, so it's cool that it's done automatically, but if you need something different like IsNew = True when the object doesn't exist in the db, you can't do it because it will be overriden by the dp.
The flexibility comes in that whatever you do inside Fetch() sticks. Right now, it doesn't matter if you call MarkNew, MarkDirty or whatever, it will all be disregarded because of the MarkOld call done in the dp.


Ok, I can agree with that.  Still would suck to have to change my existing code though.  Wink [;)]

xal:
About overriding InvokeCompleted, it would be a pain, because you don't have an easy way of knowing whether the object was retrieved or not from the db unless you set some var indicating that it was loaded or it is new. Inside fetch, you could easily do if (dr.Read()) { ... } else { MarkNew(); }.

That is very straight forward, and doesn't require overriding an "outside method" that doesn't know much about what happened during the fetch (unless you explicitly store that info somewhere).


Perhaps this is an argument against having a Fetch return a new object.  I haven't yet come across a case where it made sense to do that, and you're blurring the definition.  After all, Fetch means 'load from database,' not 'load from database if possible, new otherwise.'

Andy

JoeFallon1 replied on Wednesday, October 11, 2006

Perhaps this is an argument against having a Fetch return a new object.  I haven't yet come across a case where it made sense to do that, and you're blurring the definition.  After all, Fetch means 'load from database,' not 'load from database if possible, new otherwise.'

============================================================

But this is exactly how I define my Fetch code. So now it looks like it is broken under Csla2 because the DP calls Mark Old for you. Hmm. Looks like I might have to comment it out until Rocky changes it to either Before Fetch or uses the Args idea.

Joe


 

ajj3085 replied on Thursday, October 12, 2006

JoeFallon1:
But this is exactly how I define my Fetch code. So now it looks like it is broken under Csla2 because the DP calls Mark Old for you. Hmm. Looks like I might have to comment it out until Rocky changes it to either Before Fetch or uses the Args idea.


Joe, what exactly is the requirement that precludes you using Create to create new objects, and instead trying to have fetch do both fetching or returning a new object?

I'd like to know, because it does seem kinda odd for Fetch to be returning New objects.  It seems this is kind of the crux of the argument to have MarkOld called before DP_F, to accomodate this scenario.  Is there any other reason the added flexibity would be needed except for this scenario?

While it might be nice for the framework to support this, that doesn't seem to be the intended way the framework is intended to be used. 

I'd like to add that this I think this is probably a good change to make, but I think careful consideration needs to be given to this because fetch and creation operations are more easily blurred, which may not be a good thing..

ajj3085 replied on Thursday, October 12, 2006

JoeFallon1:
But this is exactly how I define my Fetch code. So now it looks like it is broken under Csla2 because the DP calls Mark Old for you. Hmm. Looks like I might have to comment it out until Rocky changes it to either Before Fetch or uses the Args idea.


Joe, what exactly is the requirement that precludes you using Create to create new objects, and instead trying to have fetch do both fetching or returning a new object?

I'd like to know, because it does seem kinda odd for Fetch to be returning New objects.  It seems this is kind of the crux of the argument to have MarkOld called before DP_F, to accomodate this scenario.  Is there any other reason the added flexibity would be needed except for this scenario?

While it might be nice for the framework to support this, that doesn't seem to be the intended way the framework is intended to be used. 

I'd like to add that this I think this is probably a good change to make, but I think careful consideration needs to be given to this because fetch and creation operations are more easily blurred, which may not be a good thing..

JoeFallon1 replied on Thursday, October 12, 2006

It isn't so much a requirement as it is that is how I built the Fetch method years ago. In the old forum there were lengthy discussions about this and half the people came down on the side of returning new and the other half wanted to return Nothing or throw an exception. Since I had an app to build I picked one of the methods and now all of my code expects that behavior. If the behavior were to suddenly change I have no idea how many pages would break.

 Protected Overrides Sub DataPortal_Fetch(ByVal criteria As Object)
      If TypeOf criteria Is CriteriaCode Then
        Dim crit As CriteriaCode = DirectCast(criteria, CriteriaCode)
        If RecordDoesNotExist(crit.Code) Then
          Me.DataPortal_Create(criteria)
        Else
          DoFetch(criteria)
        End If
      End If
End Sub

Protected Overridable Sub DoFetch(ByVal criteria As Object)
      SetDefaults()

      Dim cn As IDbConnection
      Try
        cn = DAL.CreateConnection
        cn.Open()
        PreFetchData(criteria, cn)
        FetchData(criteria, cn)
        PostFetchData(criteria, cn)
        FetchChildren(criteria, cn)
      Finally
        cn.Close()
      End Try

      ValidationRules.CheckRules()
    End Sub

 

Joe

 

ajj3085 replied on Thursday, October 12, 2006

Well the current behavior in Csla 2 will break your apps then.

I think before any decision to change the current behavior is made, we need to answer the question 'should the framework really support creating new objects in the Fetch methods?'  Kinda feels to me that fetching is for fetching, and if you really want a new object you should be going through create.

Andy

RockfordLhotka replied on Thursday, October 12, 2006

Certainly my view is that Fetch is for get, and Create is for new. Fetch shouldn't return a new object. If you need to go to the server and do a Create or Fetch and return the result, then use a factory object (probably ReadOnlyBase-derived).

But to step back to Xal's original point, there's a good argument to be made that IsNew should be false before your DP_F code runs.

However, it is quite clear that IsDirty needs to be reset to false after DP_F runs, or untold amounts of code would be badly broken.

So would it work to set IsNew to false before DP_F, and both IsDirty and IsNew to false after DP_F?

ajj3085 replied on Thursday, October 12, 2006

That sounds like a workable idea.

JoeFallon1 replied on Thursday, October 12, 2006

 IsNew should be false before your DP_F code runs.

However, it is quite clear that IsDirty needs to be reset to false after DP_F runs, or untold amounts of code would be badly broken.

So would it work to set IsNew to false before DP_F, and both IsDirty and IsNew to false after DP_F?

No. It would not work. You are still setting IsNew to False AFTER the fetch. In my code it is a breaking change. There were a lot of other people who coded their BOs this way too in the old forum. I didn't just make up this idea of returning New if the record is not found. They may not be participating in this new forum as vocally as some people but this issue should not be discounted.

FWIW - I wasn't aware it was a breaking change in 2.0 until this thread pointed it out.

I am not in Production code yet - but will be soon. So I have only done light testing and missed this point.

What is wrong with this?
set IsNew to false and IsDirty to false before DP_F.

Then if I happen to branch over to DP_Create I will have to call MarkNew
and set IsNew=True and IsDirty=True. Then when Fetch returns there is no call to re-set these values since it happened before the Fetch.

==================================================================

Inside SimpleDataPortalFetch just move one line of code:

        MethodCaller.CallMethodIfImplemented(obj, "MarkOld")

        ' tell the business object to fetch its data
        Dim method As MethodInfo = MethodCaller.GetFetchMethod(objectType, criteria)
        If TypeOf criteria Is Integer Then
          ' an "Integer" criteria is a special flag indicating
          ' that criteria is empty and should not be used
          MethodCaller.CallMethod(obj, method)

        Else
          MethodCaller.CallMethod(obj, method, criteria)
        End If

        ''' mark the object as old
        '''MethodCaller.CallMethodIfImplemented(obj, "MarkOld")

I just tested it and the BO is set correctly:

mIsNew = False

mIsDirty=False

=====================================================

Note: the exact same issue exists in SimpleDataPortal_Create

 

        ' mark the object as new
        MethodCaller.CallMethodIfImplemented(obj, "MarkNew")

       ' tell the business object to fetch its data
        Dim method As MethodInfo = MethodCaller.GetCreateMethod(objectType, criteria)
        If TypeOf criteria Is Integer Then
          ' an "Integer" criteria is a special flag indicating
          ' that criteria is empty and should not be used
          MethodCaller.CallMethod(obj, method)

        Else
          MethodCaller.CallMethod(obj, method, criteria)
        End If

        ''' mark the object as new
        '''MethodCaller.CallMethodIfImplemented(obj, "MarkNew")

================================================================

 

Joe

 

PS - some quick tests show the BO is returned in the correct state (as far as IsNew and IsDirty are concerned) for both DP_Create and DP_Fetch if you move the code to before the methods are called. Not sure where you need to call OnUnknowPropertyChanged when fetching.


 

ajj3085 replied on Friday, October 13, 2006

JoeFallon1:
No. It would not work. You are still setting IsNew to False AFTER the fetch. In my code it is a breaking change. There were a lot of other people who coded their BOs this way too in the old forum. I didn't just make up this idea of returning New if the record is not found. They may not be participating in this new forum as vocally as some people but this issue should not be discounted.

FWIW - I wasn't aware it was a breaking change in 2.0 until this thread pointed it out.

I am not in Production code yet - but will be soon. So I have only done light testing and missed this point.

What is wrong with this?
set IsNew to false and IsDirty to false before DP_F.

To be fair, its only a breaking change if you went against the grain so to speak.  Implementing your suggestion would break all of my code because I set the object state via properties which changes the IsDirty flag.  Many people may have done New in a Fetch, but it doesn't sound like Rocky ever supported doing so..

The suggestion of setting IsNew before the DP_F is a good idea though, because there is a legitmate need to base rules off of the IsNew status, which was the original problem this thread was addressing.  It makes sense too, if you're fetching an object there's nothing wrong with having rules based off its New or Old status; I remember this being discussed in the book.

JoeFallon1 replied on Friday, October 13, 2006

"To be fair, its only a breaking change if you went against the grain so to speak.  Implementing your suggestion would break all of my code because I set the object state via properties which changes the IsDirty flag."

To be fair - you are going against the grain here too. Rocky specifically recommends NOT setting state during fetch using Properties. It not only changes the flag, it raises the events and rule checking. If you did it the way Rocky recommends then the recommended change would not be an issue for you plus it would solve the issue for me.

In your case, if Rocky made the change to set IsDirty before the Fetch then your code could be fixed by adding MarkOld to the end of your Fetch. The call would not be needed if you used the fields to set the values.

Joe

 

 

 

RockfordLhotka replied on Friday, October 13, 2006

So what I'm hearing is that I can do this
  1. Call MarkOld() before DP_F
  2. Call MarkClean() after DP_F
And everyone will be happy?

The only drawback to this, is that that it would trigger OnUnknownPropertyChanged() twice. I'm not convinced that's a serious issue though - because the object is being newly created and thus can't be bound to anything yet, so it should be impossible for any event listeners to exist at this point in the lifecycle.

ajj3085 replied on Friday, October 13, 2006

That would work for me, although it seems there's a lot of sides, so may the automatic call should just be dropped completely to give people the flexibility they want.

It might also make things more consistent, since right now the call can only work on root objects, you still have to call Markxxx yourself for child objects... unless there's something I missed.

Andy

Mark replied on Friday, October 13, 2006

I tend to agree.  By introducing the MarkOld() call into DP_Fetch, we've introduced a secondary behavior into the method and coupled the Fetch behavior to marking it old.  As we've seen in these posts, that may not be the desired behavior.

I'd vote for removing it from DP_Fetch altogether, even though it's a breaking change for 2.0 code.  It allows each developer to code the DP_Fetch to his/her needs.

For what it's worth...

JoeFallon1 replied on Friday, October 13, 2006

RockfordLhotka:
So what I'm hearing is that I can do this
  1. Call MarkOld() before DP_F
  2. Call MarkClean() after DP_F

And everyone will be happy?

 

Rocky,
I don't think you can make everyone happy. I think the above would not work for me.

At this point I agree with Mark and Andy that removing the call from the framework is the best thing to do. Unexpected behaviors are eliminated at the cost of having to add MarkOld to the end of Fetch method for a Root BO. As noted in the book - developers need to do this for Child BOs anyway so it is more consistent.

Don't forget that Create has the same issue so if you remove it from Fetch you should also remove the corresponding code from Create.

Don't forget the reason this whole debate started was that the call to CheckRules fails because MarkOld is called after the Fetch routine and the BO is in the wrong state. Since many developers "do not trust the database" they follow the recommendation to call CheckRules after a Fetch (or a Create). This means they need to MarkOld *before* they call CheckRules which makes the framework call to MarkOld redundant.

Joe

Brian Criswell replied on Friday, October 13, 2006

I think I am going to fourth the motion for removing the calls.  On the upside, it will make root and child objects consistent.  I think that one of the ways of evaluating the value of a framework is by how much it does for you, but in this case I think it might be getting in the way a bit too much.

JoeFallon1 replied on Monday, October 16, 2006

Looking for some feedback from Rocky on these comments.

RockfordLhotka replied on Monday, October 16, 2006

Brian Criswell:
I think I am going to fourth the motion for removing the calls.  On the upside, it will make root and child objects consistent.  I think that one of the ways of evaluating the value of a framework is by how much it does for you, but in this case I think it might be getting in the way a bit too much.


I'm in the middle of several things at the moment and haven't had time to chase this further.

I will say this: prior to this discussion I was researching ways to further automate some of these behaviors - specifically for child objects. I would much prefer if the data portal could automate the state management for all objects in the graph rather than just the root objects.

Remember that we're not just talking about DP_F here - but also _I, _U, _D and _DS. If I remove the calls, then everyone would be back in the 1.x mode of having to make the appropriate calls in all these different methods - and one of the more common causes of bugs was to forget the MarkOld() call in _U...

So while I understand the desire to (mis-)use DP_F for purposes other than fetching, I'm not ready to so easily give up on having CSLA automate away one of the most common sources of bugs in hand-written code.

At the same time, there's no doubt that Xal's original comment is totally valid - IsNew should be false before DP_F is run, so validation rules can work correctly. And there's no doubt that (at a minimum) IsDirty should be false after DP_F completes to meet the definition of dirty/clean.

Now if we can figure out a way so the default behavior automates the process, but where you can override that behavior to eliminate or change the default, that may be interesting. Especially if that can extend to my ideas around automating the process for child objects as well.

(As an aside - my goal for child objects is to reduce or eliminate the code you need to write to cascade all data calls to the children. This new concept would be optional, and the existing techniques would continue to work. In other words, this further automation would be opt-in, for the cases where further code/complexity reduction was desirable.)

Mark replied on Monday, October 16, 2006

Just thinking out load here - if the framework sets IsNew to false before calling Fetch, and Fetch throws an exception, the framework doesn't have to worry about resetting the value back to IsNew=true since we won't have a valid object anyway, right?

I'm all in favor of having the framework handle the repetitive, plumbing-type code as much as possible.   However, it appears many of us have differing viewpoints on how to use Fetch (I do think it should only be for fetching, not creating, myself).  Some call CheckRules() after loading from the db, others trust the data - some set via properties, others via fields, etc, etc.  You can't please everyone all of the time, so damn us all and remove the call to MarkOld.  :-)

However, as far as I can tell from all the posts, the only method at issue here is Fetch().  I don't see any problem in allowing the DataPortal to continue calling MarkOld() during Insert/Update and MarkNew() during Deletes.

Maybe we need an enhanced version of Fetch (using events, virtual methods, whatever).  Maybe BeforeFetch(), DataPortal_Fetch(), AfterFetch() - something like that.  The default implementation for BeforeFetch/AfterFetch in CSLA would be <whatever>, and we could override the methods if desired.  No changes to existing code if we want the default CSLA behavior.

ajj3085 replied on Tuesday, October 17, 2006

In the case of an exception, I don't think you'll be getting the object back at all, if I remember the code correctly.

I don't think just fetch should have those methods, it would make things inconsistent. 

Setting via properties / fields, or whether Validation is done or not aren't big issues, whereas redefining fetch to fetch - create is a more fundamental change.  Its helpful that there's a clear deliniation between the operations, otherwise we may just as well have a DataPortal_DoWork method and have that figure everything out (what operation needs to be done).  It may be more flexible, but its not as clean / easy to maintain.

ajj3085 replied on Tuesday, October 17, 2006

I do like the automatic calling of MarkOld / MarkNew myself, I only suggested removing as  a compromise.  I of course would prefer they stay (and it would be nice to have this done for children as well).

I've been slowly going through head first design patterns, and came across the interator + composite patterns (which I think will be helpful for something else I'm doing).  Perhaps these patterns would help?  In this case the iterator could have a MarkOld / MarkNew which the DP could use?  Or maybe I'm trying to force something into a pattern that I shouldn't be.

Andy

Henrik replied on Tuesday, October 17, 2006

I too am in favor of keeping the automatic behaviour. I was one of those who forgot to mark my objects as old all the time in the earlier versions.

However, to accommodate all users of the framework, would it be possible to create an attribute which would tell the framework, not to do automatic MarkOld and the likes. Then the developer that needs to handle this manually could mark the DP_F method with this attribute.

It may be a bit of a hack, though

/Henrik

RockfordLhotka replied on Tuesday, October 17, 2006

Henrik:

However, to accommodate all users of the framework, would it be possible to create an attribute which would tell the framework, not to do automatic MarkOld and the likes. Then the developer that needs to handle this manually could mark the DP_F method with this attribute.



Yes, the attribute idea is certainly an option. I'd prefer a solution that allows for overriding though.

If you step back and think about it, what we're after here is pre- and post-processing, but in a more specialized manner than you can easily achieve with the existing invoke and invoke complete methods. It may be the case that I should add eight new methods - pre_c, post_c, pre_f, post_f, etc. They'd all be virtual, with default behaviors. And they'd all be attributed as advanced to hide them in intellisense in the normal case.

ajj3085 replied on Tuesday, October 17, 2006

This sounds like a suggestion I had made; adding an extra parameter to the event arguments for Invoke and invokeComplete so that you can figure out what is going on.

The default Invoke / InvokeComplete could then handle those tasks. 

Maybe the event args could also include the criteria used to invoke the DP method, for Create, Fetch and Delete.

Ioannis replied on Friday, October 20, 2006

ajj3085:

This sounds like a suggestion I had made; adding an extra parameter to the event arguments for Invoke and invokeComplete so that you can figure out what is going on.

The default Invoke / InvokeComplete could then handle those tasks.&nbsp; Maybe the event args could also include the criteria used to invoke the DP method, for Create, Fetch and Delete

I definitely agree with this.

For my opinion, an object is not old while fetching, and cannot be old unless all its data is loaded. Including children objects. Additionally an object is dirty while fetching.

On the other hand, I haven’t defined such dependencies in my design yet.

Mark replied on Tuesday, October 17, 2006

Introducing the virtual methods is probably the way to go.  IMHO, the DataPortal should only be responsible for the supporting the mobile-object concept.  It really shouldn't be responsible for setting the state of the object - that should be handled internally by the object itself.  The DataPortal can indirectly trigger this - by making calls to pre_fetch, fetch, and post_fetch (or whatever they happened to be called).

 

guyroch replied on Wednesday, October 11, 2006

xal:
Hey guyroch! How was your csla vacation? Smile [:)]

I go _under_ during the summer - reconnecting with nature and the family :) 

 

xal:

** The current implementation has another problem too. Some people (I haven't had the need to do this yet, but it's something some people might want) make the fetch NOT fail if there's no data on the db, and just return a "new" object with that id if it does not exist.
Now, in that scenario, you'd normally want to call MarkNew in the fetch, but it won't do much good because the dp will mark it as old later. So, in any case, I think this things should be called before DataPortal_Fetch, so that we get more flexibility.

My approach with this would be more to just catch the RecordNotInTableException (or whatever exception you deemed appropriate) and then return a complety "new" object instead of toying toying with the fetch object.  I not sure I would have the BO do this though, I guess it depends on the use case.

just my 2 cents here

ajj3085 replied on Wednesday, October 11, 2006

Ya ya ya.. Wink [;)]

I like to pretend that the fields don't exist when possible, makes things slightly easier.  Also, there's nothing in the property setter I don't want run anyway, usually.  In those cases I used fields.

malloc1024 replied on Tuesday, October 17, 2006

You can keep the MarkOld and MarkNew calls automatic if code the GetXXX shared function in BusinessBase and provide a hook into it.  The hook would be called after MarkOld and MarkNew.  The GetXXX  function would have to return a BusinessBase object instead of the concrete object though. This is similar to the template pattern.  This pattern works well when you want a framework to automate some call for you.  I haven't read the whole thread so I am not sure if this was alread suggested.  Would this work in this situation?


Copyright (c) Marimer LLC