StrataFrame Forum

How to add several custom fields to a BO

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

By Greg McGuffey - 11/16/2006

I am attempting to add several custom fields to a BO. Following the instructions in the tutorial, you need to add GetCustomBindablePropertyDescriptors override for the property. What do you do if you have 4 properties (or any number larger than 1?



A second question is related to best practices. I have a linking table, I.e. it links rows from two different tables, say WidgetsID to a FactorID. I want to be able to show the widgets at a factor, and be able to provide some details about the widget. Is it a good idea to use custom properties in the linking BO to do this. I.e. the linking BO will have three fields, the pk field, the WidgetID field and the FactorID field. Is is a good idea to add a WidgetName and WidgetDescription custom field, that use ExecuteScalar() to retreive the name and description using the current row WidgetID? If it isn't a good idea, why? And is the alternative to use a BO to a view?



Thanks!
By Trent L. Taylor - 11/16/2006

What do you do if you have 4 properties (or any number larger than 1?

Create a descriptor for each one.  If you are using the ReflectionPropertyDescriptor, just return an array of the descriptors:

Protected Overrides Function GetCustomBindablePropertyDescriptors() As MicroFour.StrataFrame.Business.FieldPropertyDescriptor()
        '-- Return the array of property descriptors
        Return New MicroFour.StrataFrame.Business.FieldPropertyDescriptor() { _
            New ReflectionPropertyDescriptor("custom_1", GetType(MyBO)), _
            New ReflectionPropertyDescriptor("custom_2", GetType(MyBO))}
    End Function

Is is a good idea to add a WidgetName and WidgetDescription custom field, that use ExecuteScalar() to retreive the name and description using the current row WidgetID?

Calling a scalar method is always a good idea when it relates to retrieving a single piece of data...if you put a packate sniffer on your NIC, you will see very little fluff as opposed to a SELECT.  This is why the scalar exists and this is what I would do in this case.

By Greg McGuffey - 11/16/2006

Ah...light bulb goes on. My brain was refusing to comprehend the curly braces....an array...doh! I'm glad to hear that the approach I'm using is good, cause it makes coding easy and makes the linking BOs very useful, without having to add a bunch of gunk to them.



BTW, in the tutorial help file, it refers to a help topic "Creating Custom Field Properties" is referred to in the "Adding Custom Field Properties" topic (in the tutorial). The "Creating Custom Field Properties" doesn't exit. It says that if the custom property is going to be bound or used a lot, then a custom field descriptor is better. I very likely will need this at some point soon, so I'll be bugging you all for more info (or for the missing help topic) BigGrin
By Trent L. Taylor - 11/16/2006

I will look into the missing help topic.  Thanks.
By Greg McGuffey - 11/16/2006

It just occurred to me, is it better to use ExecuteScalar() directly or to use the parent BO and a Get method that uses execute scalar? I.e. which is better



LinkBO - connects to tblWidgetFactoryLink

WidgetFactoryLinkID - pk for tblWidgetFactoryLink

WidgetID - reference to Widget, from tblWidgetFactoryLink

FactoryID - reference to Factory, from tblWidgetFactoryLink

WidgetName - custom property using "Select WidgetName From tblWidget Where WidgetID = @id", @id = currentrow WidgetID, ExecuteScalar(cmd)



OR



LinkBO - connects to tblWidgetFactoryLink

(same fields as above, except...)

WidgetName - custom property using the WidgetBO.GetWidgetNameByID(currentrow WidgetID)



It seems to me that in the first case, you have coupled the LinkBO to the database, while in the second you have coupled it to the WidgetBO. Are there performance issues using the second way? Does the second way improve flexibility, say when moving from a database to a web service?
By Trent L. Taylor - 11/16/2006

It just occurred to me, is it better to use ExecuteScalar() directly or to use the parent BO and a Get method that uses execute scalar?

Going through the BO is easier when you are working within the BO.  The speed will be the same in either case.  The BO calls the code like this:

MicroFour.Data.DataBasics.DataSource(Me.DataSourceKey).ExecuteScalar(PassedCommand)

Are there performance issues using the second way? Does the second way improve flexibility, say when moving from a database to a web service?

If they have the same data source key then it makes no difference as they will both execute the command on the same connection...and ExecuteScalar never updates the internal data table.  Obviously, logic generally lends itself to looking at the object that will always be available.

By Greg McGuffey - 11/16/2006

Trent L. Taylor (11/16/2006)
Going through the BO is easier when you are working within the BO. The speed will be the same in either case. The BO calls the code like this:



MicroFour.Data.DataBasics.DataSource(Me.DataSourceKey).ExecuteScalar(PassedCommand)







This is how the BO internally executes the command right? The code I'd use it to just call the BO's appropriate Get command that uses ExecuteScalar, right?



It's taking a bit of time, but I think I'm starting to get this stuff a big BigGrin Hope you all don't die of impatience first.
By Trent L. Taylor - 11/16/2006

This is how the BO internally executes the command right? The code I'd use it to just call the BO's appropriate Get command that uses ExecuteScalar, right?

Yes, I was just showing the internal code of:

MyBO.ExecuteScalar()

It's taking a bit of time, but I think I'm starting to get this stuff a big Hope you all don't die of impatience first.

I am glad to hear that you are making progress.  Don't worry about the questions, that is what this forum is for!

By Greg McGuffey - 11/16/2006

I don't suppose there is an interface for BusinessLayer is there? I have a set of Business objects that all have some common functionality, albeit affecting different tables. Specifically, they all have ordered records, which means there is a set of common things that can happen, like moving a record up or down in the order or determining the next sequence number. I would like to program against a common interface, but I also need the standard BusinessLayer functionality (add, edit, save, undo, remove, events etc.) If there was an interface to BusinessLayer, I could just extend it. If there isn't I could use some suggestions.
By Trent L. Taylor - 11/16/2006

You don't need an interface in this case as you would have to re-write the code in every BO that implemented it.  However, you can inherit the BusinessLayer.  Just create your own BO and then when you create a new business object, just change the inherits to your business layer class and it will use all of your modified code and features:

Public Class MyCustomBusinessLayer
    Inherits MicroFour.StrataFrame.Business.BusinessLayer

   '-- Add Your Stuff
End Class

Then when you create a new business object through the Add Item template, you will need to adjust the inherits the first time (you will notice that the only BO code file that has a inherits declaration is in the MyBo.vb file.  This is so the BO Mapper does not overwrite your inherits statement when changed to use your BO class.  It would look like this in this example:

<Serializable()> _
Public Class MyNewBO
    Inherits MyCustomBusinessLayer
   '-- all of the other template code will be here...
End Class
By Greg McGuffey - 11/16/2006

Actually, the reason I was looking at an interface was that I have another class (a user control actually) that would interface with the common functionality of the special BOs. I.e. I need to reference the Interface in the other class, so I can call the known methods (the BOs will all have sequencing functionality, like MoveItemUp, MoveItemDown, etc.). Each BO would implement the methods as needed by the particular table.

What I ended up doing was to just create two variables, one as a BusinessLayer item and one as my interface item (IParentSequencerBO). Then provided a single public property for the BusinessLayer variable, set the interface variable to the same object. It seems to be working great. E.g. below in case my narrative is confusing.


Public Class MyClass

private _bo as Microfour.StrataFrame.Business.BusinessLayer
private _seqBO as IParentSequenceBO
private _idField as String

Public Property IDField(fieldName as string)
Get
IDField = _idField
End Get
Set(ByVal value As string)
_idField=value
End Set
End Property

Public Property BO As Microfour.StrataFrame.Business.BusinessLayer
Get
BO = _bo
End Get
Set(ByVal value As Microfour.StrataFrame.Business.BusinessLayer)
_bo = value
_seqBO = value
End Set
End Property

Public Sub MoveDown()
'-- Call a method of the BusinessLayer
Dim id As Int32 = _bo.Item(Me.IDField)

'-- Call a method define by the interface
_seqBO.MoveItemDown(id)
End Sub
End Class


If you have a better idea, I'm all ears.
By Greg McGuffey - 11/16/2006

OK, what is the correct tag for code snippets. Obviously, the one's I'm using are correct. Sad
By Trent L. Taylor - 11/17/2006

What you are doing will definitely work.  There are two other things that you could do.  First, tack this on to my first example...create your own interface, as you have, and then associated this interface with your custom BusinessLayer class.  This is more structured and will be much easier to work with as your application grows.

Public Class MyCustomBusinessLayer
    Inherits MicroFour.StrataFrame.Business.BusinessLayer
    Implements IParentSequenceBO
   '-- Add Your Stuff
End Class

As for your code snippet, I edited your post and then saved and it worked. There could be underlying characters that are being pasted in with your code causing the problem.  One thing to do is to paste it into notepad first then copy it from there.  THis way all special characters are stripped.

By Greg McGuffey - 11/17/2006

That is exactly what I'm doing. I'm going to have half dozen or so BOs that all have this sequencing functionality. With this interface I can build a reusable UI control/component to re-sequence elements within the BO. Though I might suggest that you provide a IBusinessLayer interface in the future. It would make this sort of thing easier. Then I could just inherit that interface for any of my own and life would be grand BigGrin
By Trent L. Taylor - 11/17/2006

I don't think I can explain this properly over the forum, but there is no need for an IBusinessLayer interface.  An interface is not the solution here...you can use the BusinessLayerBase class, which you will find commonly throughout the framework and in typed editors, etc.  This will give you the base functionality and will allow any type of BO to be handed over to a variable or property typed as this...but I still do not see a need for the IBusinessLayer interface. 
By Greg McGuffey - 11/17/2006

Trent L. Taylor (11/17/2006)
I don't think I can explain this properly over the forum...




I just wrote out a long explanation of why an IBusinessLayer interface would be helpful when I think I get what you are saying about using a concrete class....



So, I create a new class, lets say ParentSequencerBO. This would not hit any tables right (and thus would always have a red X by it in the BO mapper)? it would look something like:





Public MustInherit Class ParentSequencerBusinessLayer

Inherits BusinessLayer



' Abstract methods...but they could be actual methods too, if code

' could be generalized

Public MustOverride Sub MoveItemUp()

Public MustOverride Sub MoveItemDown()



End Class





Then I would derive my actual BOs from it:





Public Class ProcessStepBO

Inherits ParentSequencerBusinessLayer



Public Overrides Sub MoveItemUp()

' ...code

End Sub

Public Overrides Sub MoveItemDown()

'....code

End Sub

End Class





Then my User control would reference the abstract class ParentSequencerBusinessLayer and I'm good. See, I think you got it across here in the forum (if I'm getting it)! Tongue



P.S. the [codesnippet][/codesnippet] isn't working. I double checked for weird characters, pasted into and out of a text editor...but no joy. Maybe it is user permission thing?