I have two class:
TransactionBase (my base class) and ProductTransaction (my derived class, that derives from TransactionBase.
In TransactionBase, I set the "DataPortal_Create" method with a RunLocal attribute because I do not need to get anything from the database
However, when I use the ProductTransaction, I want to go out to the database on the Create method (i.e. ProductTransaction.NewRoot()). So, if I override the "DataPortal_Create" method in my derived class, will that RunLocal Attribute disappear and the NewRoot method call WILL go out to the server?
ward0093
Great, Thanks...
I kind of figured that (and had not testing mechanism setup)... but wanted to make sure
ward0093
I have tested this scenario.
The RunLocal() attribute seems to be inherited by a method that overrides the one in the base class. (Or at least it is determined to exist by Rocky's code, so the effect is the same.)
I just stepped through the code and found that it returns True when the Base class has the atrribute on it even though the methodInfo is from the final type.
The methodInfo is found here: Note the specific use of oneLevelFlags. The hierarchy is not supposed to be flattened with this call. ====================================================================
Public
Function FindMethod(ByVal objType As Type, ByVal method As String, ByVal types As Type()) As MethodInfo Dim info As MethodInfo = Nothing Do ' find for a strongly typed matchinfo = objType.GetMethod(method, oneLevelFlags,
Nothing, types, Nothing) If info IsNot Nothing Then Exit Do ' match found End IfobjType = objType.BaseType
Loop While objType IsNot Nothing Return info End Function====================================================================
Private Function RunLocal(ByVal method As MethodInfo) As Boolean Return Attribute.IsDefined(method, GetType(RunLocalAttribute)) End FunctionThe Base type is part of the methodInfo too and maybe the function above *does* flatten the hierarchy so that it it returns True when it should be False. The documentation says is should not do so. A third Boolean parameter can be used to "determine whether any custom attributes are applied to a member of a type. Parameters specify the member, the type of the custom attribute to search for, and whether to search ancestors of the member."
Now I am not sure why it works this way, but it does. I guess it would help if someone else could weigh in on this and let us know why it is acting this way.
This is why I decided to omit the RunLocal attribute from my Base class but add it to my developer level class which is the final type. This way I can codegen both classes and have RunLocal as a default. But then as a developer I can remove the attribute on the final type if I need to hit the DB.
===============================================================
Update:
here is the code from the command window using the 3rd Boolean parameter:
>? Attribute.IsDefined(method, GetType(RunLocalAttribute), True)
True
>? Attribute.IsDefined(method, GetType(RunLocalAttribute), False)
False
Apparently the 3rd parameter defaults to True and it was omitted by Rocky who probably assumed it was False. So it seems there is a bug in the CSLA code for the RunLocal function. It should read:Return
Attribute.IsDefined(method, GetType(RunLocalAttribute), False)Joe
shoootttt!!!!.... this is no good!!!
I have something like 100 objects.., I am going to have to add "RunLocal" to all those classes.
There must be a better way!... can someone way in on this? Rocky?
ward0093
thanks Andy, but do you have an example of how to do that?
also... does this mean that none of our Bis Classes have to have the <Serializable()> Attribute applied? Because it is already applied to the base classes?
ward0093
ward0093:wait... Andy... that will not work either, because then the attribute will not be applied to any of our other classes correct... I mean, we can not use a BaseClass in our BO Library with the RunLocal Attribute applied if it is not inherited to all the other derived classes... correct?
The simplest fix would probably be to change this one line of code in the CSLA 2.1 framework.
Then it would act "correctly". You could codegen the <RunLocal> attribute for all your base classes. All derived classes would use it. If you need to Override DP_Create in a derived class you could omit the attribute and talk to the DB because you would have gone through the Data Portal.
But it would be nice if Rocky or someone else could confirm the behavior first. And even nicer if Rocky were to make the change. (I am trying to not modify the framework in 2.x if I can help it. I want to extend it using my own code where possible.)
Return Attribute.IsDefined(method, GetType(RunLocalAttribute), False)
Joe
Andres,
No need to apologize for the "wrong" post. I had known about this behavior for a while and had even built it into my Codesmith templates. So I was surprised to see your comment. That is what lead to some deeper digging and exposed the possible bug. In other words, without the bug, your comment would have been spot on.
Joe
ajj3085:Technically I'm not sure if its a bug or by design.. we'll have to wait to see what Rocky says.
I got a message from Rocky.
He said he would change it in 2.1 because:
"I certainly _expected_ false to be the default."
Joe
Now that we are here... I am confused on what the solution is going to be
Will I have to mark all my BO Classes - DB_Create methods with the RunLocalAttribute because it is not Inheritable? Not sure I like that... becuase I have to touch over 100 code files.
Then again... that might be the only way to get the functionality we need.
is that how it is going to work?
ward0093
Well, let's define where "here" is first. <g>
The original problem is:
==========================================================
TransactionBase (my base class) and ProductTransaction (my derived class, that derives from TransactionBase.
In TransactionBase, I set the "DataPortal_Create" method with a RunLocal attribute because I do not need to get anything from the database
However, when I use the ProductTransaction, I want to go out to the database on the Create method (i.e. ProductTransaction.NewRoot()). So, if I override the "DataPortal_Create" method in my derived class, will that RunLocal Attribute disappear and the NewRoot method call WILL go out to the server?
ward0093
==========================================================
This response would be correct if there was no bug:
Yes, it will go to the remote dp. The RunLocal() attribute is not inherited by a method that overrides the one in the base class.
==========================================================
Once the bug is fixed, then your Base classes will all have the RunLocal attribute in them.
Unless you Override DataPortal_Create then all of your final types will use the base method and run locally.
For those Types where you do override DataPortal_Create, if you omit the attribute then it is not inherited so you can run remotely to the database.
The only files you have to "touch" are those where you override DataPortal_Create.
Joe
Copyright (c) Marimer LLC