StrataFrame Forum

BO default properties

http://forum.strataframe.net/Topic6705.aspx

By Peter Jones - 2/11/2007

Hi,

Is there any way of changing the 'default property values' when a new BO is created? For example the default AllowNullValuesOnNewRows is False and it may be that, in most cases, we would like that value to be True in which case it would be useful if we could have all new BO's start with a AllowNullValuesOnNewRows of True.

Cheers, Peter 

By Trent L. Taylor - 2/12/2007

You can create your own BusinessLayer by subclassing the StrataFrame BusinessLayer.  The Inherits is added in the primary class and not the designer file.  The reason for this is exactly as you have described.  You can subclass our BusinessLayer and then when you create a new BO, change the inherits one time.  This will never be overwritten since the inherits statement is not in the file that gets modified by the BO Mapper.

Public Class MyBusinessLayer
    Inherits MicroFour.StrataFrame.Business.BusinessLayer

    '-- Overwrite any behavior here or change default values
End Class

By Peter Jones - 4/3/2007

Hi Trent,

Just getting round to creating a base BO class for our apps. All is fine except I get the error: Too many arguements in Public Sub New() in the BO that inherits from our modified BO. This happens in the New overload:

Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
  MyBase.New(info, context)
  'This call is required by the Component Designer.
  Me.InitializeComponent()
  '-- Add the necessary handlers
  Me.AddHandlers()
End Sub

If I comment this overload out all is ok but being new to .Net/Subclassing etc I have no idea if this is ok or not. I realise this is not a StrataFrame issue and I'm not looking for a Subclassing 101 course but any insight would be appreciated.

However I do have a couple of StrataFrame specific questions.


My base BO sets default values for certain properties and a Private Sub InitializeComponent() section of code is created containing all the new property values. How do I make the BO, that inherits from my base BO, use the code in InitializeComponent so its own properties are initialised to the same values?

Part of the new code in the base BO is a generic data load. We enter a stored proc name into the "UpdateStoredProcedureName" property of the BO so we can have generic code for populating a BO when the parent form loads. The base BO for testing this approach just has the following code:

Public Class MyBO
    Inherits MicroFour.StrataFrame.Business.BusinessLayer

    Public Sub FillBO(ByVal StoredProc As String)
        If StoredProc.Length > 4 Then
            Me.FillByStoredProcedure(StoredProc)
        Else
            'TO DO - log error and inform user
        End If
    End Sub
    Protected Overrides Sub OnParentFormLoading()
        Me.FillBO(Me.UpdateStoredProcedureName)
    End Sub
End Class


However, when my test form runs it throws the error:

ApplicationException
 An error occurred while creating the main form
TargetInvocationException
 Exception has been thrown by the target of an invocation.
NotImplementedException
 The class [TMS_Test_01.BusinessObject1] must override the property 'TableName' since it derives from MicroFour.StrataFrame.Business.BusinessLayer.

Source     : MicroFour StrataFrame UI

Stack Trace:
   at MicroFour.StrataFrame.Business.BusinessLayer.get_TableName()
   at MicroFour.StrataFrame.Business.BusinessLayer.CreateInternalTable()
   at MicroFour.StrataFrame.Business.BusinessLayer.get__CurrentDataTable(Boolean IsSharedTable)
   at MicroFour.StrataFrame.Business.BusinessBindingSource.AddBOHandlers()
   at MicroFour.StrataFrame.Business.BusinessBindingSource.set_BusinessObject(BusinessLayer value)
   at TMS_Test_01.Form5.InitializeComponent() in C:\Documents and Settings\pmj\My Documents\Visual Studio 2005\Projects\TMS_Test_01\TMS_Test_01\Form5.Designer.vb:line 99
   at TMS_Test_01.Form5..ctor()
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache)
   at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at MicroFour.StrataFrame.Application.StrataFrameApplication.RunApplication()

Line 99 in Form5 reads:
        Me.BusinessBindingSource1.BusinessObject = Me.BusinessObject11


I can see that TableName is an overrideable property but I have no idea what I should be doing here.

Cheers, Peter

 

 

By StrataFrame Team - 4/4/2007

Howdy, Peter,

You can have a public constructor (Public Sub New()) defined in a base class and you don't have to redefine it in the sub class.  What I would recommend doing is remove the constructors completely from your "base" bo class.  The reason for this is that you are going to be redefining them in your specific business object classes, so there's no need to have them both (and the template for a new BusinessObject includes the constructors).

On your second question, as long as the InitializeComponent() is called by all of the constructors in a class, then you can be pretty sure that it's going to be called.  The business objects are designed for the exact functionality you're describing... if you open the component designer for a business object, any property you set there will be placed within the InializeComponent() of that BO.  So, any instance of that BO that you create will have those values.

Any time you get a message that says "The class [class] must override the property 'property' because it derives from MicroFour.StrataFrame.Business.BusinessLayer" the property in question should be overriden within the partial class that is created by the BOMapper.  So, if you create a "base" class for all of your business objects, you're not going to use the BOMapper to create fields on it because it's the base class.  But since it's the base class, that's OK, because you won't be creating any instances of the base class directly; you'll just be inheriting it.  Therefore, any of your subclassed business objects will have overriden that field when the BOMapper generates their partial classes.  So, if you're getting that error, it's either because you didn't use the BOMapper on the business object, or you are trying to create an instance of your base class.

By Peter Jones - 4/4/2007

Hi Ben,

Thanks for the responses - question 2 ok and question 3 big mistake on my part but ok now. However regarding question 1 you commented: "...you don't have to redefine it in the sub class. What I would recommend doing is remove the constructors completely from your "base" bo class."

Actually this what we have - refer to the MyBO class code in my previous message. Even with a "base" BO class such as the example (no constructor code) we still get the same error. Am I misunderstanding your comment?

Cheers, Peter

By StrataFrame Team - 4/5/2007

Ah, I see, the problem is stemming from the way that .NET handles constructors.... if you don't define a constructor in a class, .NET defines a default constructor with no parameters for it.  So, when you call MyBase.New(info, context), your inherited class cannot see through your BO base class to the constructors within BusinessLayer because a new constructor has been defined. 

So, do this... go ahead and create the constructors in your base class, but take out all of the code except the MyBase.New(...) call and the call to InitializeComponent().  Mainly just remove your call to AddHandlers() or else the business rules and default values events will be handled twice per class (that is of course if you don't want to put any default or rules checking code in the base class... if you do, then you'll want to leave the calls to AddHandlers() so that you can check them in both places.

By Peter Jones - 4/5/2007

Thanks Ben, I'm up and running, Peter
By StrataFrame Team - 4/9/2007

Glad to hear it Smile
By Peter Jones - 4/11/2007

Hi Ben,

I thought I had this under control but I still have a few problems that I'm working through. I just want confirmation of something you said earlier: "So, if you create a "base" class for all of your business objects, you're not going to use the BOMapper to create fields on it because it's the base class.".

Do I take this to mean that my "base" BO is just a standard Windows class, i.e. not something I create using the SF Business Object template.

Cheers, Peter

By Trent L. Taylor - 4/11/2007

Do I take this to mean that my "base" BO is just a standard Windows class, i.e. not something I create using the SF Business Object template.

Not unless you want to re-write the entire business layer logic, which would be a bit involed BigGrin  Actually, what Ben is referring to is you will create a standard Windows class, then inherit that class off of the MicroFour.StrataFrame.Business.BusinessLayer class.

Public Class MyBOClass
    Inherits MicroFour.StrataFrame.Business.BusinessLayer

'-- Add your logic here

End Class

Then, you can do one of two things when creating a new BO.  1.) Use the standard SF Business Object template to create your class.  Then open the class and replace the Inherits statement from the BusinessLayer to your BO class name (i.e. MyBOClass from above).  This way when you use the BO Mapper the fields will be created just as it normally would, but all of the inherited logic will remain. 2.)  You can create your own template that already has the inherits statement.

By Peter Jones - 4/11/2007


Hi Trent,

Ok - the problem I have is that when I create my base class as a Windows class (TMS_Test_01.boBase02) I get the following error in my SF BO's that inherit from it. There is no Designer file for TMS_Test_01.boBase02 and this made me think that maybe it should have been created using the SF Business Object template.

All my classes are in a single Solution so I can't see that it can be a referencing issue and the solution has been cleaned/rebuild many times.

My class starts with the code:

Imports System.Data

Imports System.Data.SqlClient

Imports System.Runtime.Serialization

Public Class boBase02

Inherits MicroFour.StrataFrame.Business.BusinessLayer

Cheers, Peter

>>>>>>>>>>>>>>>>>>>>>>
The designer could not be shown for this file because none of the classes within it can be designed. The designer inspected the following classes in the file: boAGT2 --- The base class 'TMS_Test_01.boBase02' could not be loaded. Ensure the assembly has been referenced and that all projects have been built.
   

at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager manager)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.DeferredLoadHandler.Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferDataEvents.OnLoadCompleted(Int32 fReload)

By Trent L. Taylor - 4/11/2007

Here is a custom BO class that is inherited from the SF business layer.  I have just created this, tested it, created a new BO, and mapped to it and it works as advertised BigGrin

Public Class MyCustomBO
    Inherits MicroFour.StrataFrame.Business.BusinessLayer
#Region " Constructors "
    Public Sub New(ByVal Container As System.ComponentModel.IContainer)
        MyBase.New(Container)
    End Sub
    Public Sub New()
        MyBase.New()
    End Sub
    Public Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)
        MyBase.New(info, context)
    End Sub
#End Region
End Class
By Peter Jones - 4/11/2007

Hi Trent,

Thanks for the very prompt response. I've used your code and I still have the same problem - but at least I now know that part of the puzzle is according to Hoyle so I can now try and track down the problem in other areas.

Cheers, Peter

By Peter Jones - 4/11/2007

Hi Trent,

Maybe something has can astray in my environment. Here is what I have just done:


1. Created a Windows class, called it boBase03 and copied in your code and changed the classes internal name to boBase03.

2. Did a rebuild.

2. Created a new BO (BusinessObject2) and mapped it to a simple table and did a partial rebuild with the new BO.

3. Opening up the new BO in the IDE and no problems - could toggle ok between the BusinessObject2.vb and BusinessObject2.vb[Design] tabs. Also opened its Designer file - no problems.

4. Did a rebuild.

5. Opened my new BO and changed the inherits line to: Inherits TMS_Test_01.boBase03

6. Did a rebuild.

7. Click on the BussinessObject2.vb[Design] tab in the IDE and received the following error (same as before).

8. Changes the inheritance back to: Inherits MicroFour.StrataFrame.Business.BusinessLayer.

9. Did a rebuild.

10. Everything is ok.

11. Closed all tabs.

12. Opened BusinessObject02 and changed the inheritance back to: Inherits TMS_Test_01.boBase03

13. Clicked the BusinessObject2.vb[Design] and tab and again the same error appears.


Trent, what I did notice is that my standard (base BO - "boBase03") Windows class that now contains the code you provided also appears in the BO Mapper with the red (must be configured) cross symbol. I didn't do anything with it in BO Mapper but is this expected?

I will try repeating these tests in a new Solution.

Cheers, Peter


>>>>>>>>>>>>>>>>
The designer could not be shown for this file because none of the classes within it can be designed. The

designer inspected the following classes in the file: BusinessObject2 --- The base class 'TMS_Test_01.boBase03'

could not be loaded. Ensure the assembly has been referenced and that all projects have been built.
Hide    

at

System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager

manager)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager

manager)
at

Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationM

anager serializationManager)
at System.ComponentModel.Design.Serialization.BasicDesignerLoader.BeginLoad(IDesignerLoaderHost host)
>>>>>>>>>>>>>>>>>>>

By Peter Jones - 4/11/2007

Hi Trent,

Well doing the same as above in new Solution works just fine so I will leave that apparently corrupted Solution behind and move on. However I would appreciate some feedback on my "base bo" appearing in the BO Mapper (this also happens in my new Solution). Is this to be expected? Should I just ignore it?

Cheers, Peter

By StrataFrame Team - 4/12/2007

Peter,

The base bo is going to appear in the business object mapper... I don't think there's a way around that.  However, you can add the <HideFromExtensibility()> attribute to the top of your class to keep it from showing up in other places, like the PopulationDataSourceSettings editors, and things like that.

As for why your other should could not be designed... that's a VS thing.  When you add a new component to your solution, sometimes, the type will not be available to the VS type resolution service until you close VS and reopen it.  So, the next time you add a new base bo class: add it, build your solution, close VS, and reopen VS and you should be alright.  It's the same problem that occurs when you add a new control or business object and try to drop it from the toolbox immediately after building; sometimes it works fine, but sometimes VS gives you the error saying that the type "classname" instantiation failed and that it will be removed from the toolbox.  Same silly issue, just close VS and reopen it.