Business class property implementation

Business class property implementation

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


PAT336 posted on Monday, August 27, 2007

Hi,

My background is VFP and I am new to C#. My problem is to write huge amount of code for implementing a business class, for each data field I have to create private property, create public property with get and set code, write AddAuthorizationRules function and add one line for each writable property for 30/40 fields of table even though all my fields in general are writable to all users in all tables, write code for saving and retrieving SQL data from/to class properties.

Now if field is added or deleted I have to go to all of above places and modify code.

Is there any better way than this? Is it possible to create collection of properties, or any other way of implementation so I have to define set of field names and data types at only one place and don't have to do coding at multiple places?

Thanks

PAT336

Q Johnson replied on Monday, August 27, 2007

This is precisely why so many folks on the forum use code generation techniques of one kind or another.  You can see some other posts on the topic frequently here and in the Community Contributions section of this board. 

I think that the most popular strategy here is based on CodeSmith 2.6 and is called CslaGen. You can find out about it at:

http://www.cslagenwiki.com/~cslagenw/mediawiki001/index.php?title=CSLA_Gen_Online_Reference

and find the CSLAGen project itself (downloadable) and its own user forum at a Google Groups page:

http://groups.google.com/group/CslaGenerator

I am personally a big fan of MyGeneration, (www.myGeneration.com) which you may also want to investigate.  I'm considering moving to CslaGen just because there is so much more peer support for it.  But in the long run, I think you'll be customizing your own templates on most projects and I find this easier to do in .NET than using the asp script approach taken in Code Smith.  If you are a web developer familiar with asp, this will not be a factor for you, of course.

And if you want to get a better understanding of the whole code gen topic - a real solid foundation from which you have some perspective to judge your various options - find a copy of Kathleen Dollard's book:  Code Generation in Microsoft .NET.  Chapter Six may be a bit challenging, but you can get a great deal of value out of the rest of the book if you skim Ch 6 (or even if you just quit at chapter five). 

You can spend a lot of time on the learning curve with this before you get productive, so keep the overall goal in mind.  Get a good idea of how long it takes to create a Business Object of your average complexity.  Multiply that by the number of classes you expect to use in a typical project.  Once you have these effort levels in mind, along with some idea of the frequency with which you start new projects, you should have a good idea of how much time you're willing to invest in adding Code Generation to your arsenal.  I probably spent most of three weeks at it between reading "the book" and building my first set of templates.  But I made the time back up within a few months.  For example, I started a project with about a dozen classes a few months later and generated all the business object classes (about 3000 lines of code) in the first thirty minutes of work in Visual Studio.  (Obviously my OO design and some of my database design work was done before hand, but you have to do that SOME time <g>).

If modifying/maintaining these templates seems too much work for the few projects you'll use them for, consider the CSLA Snippet library and/or the macro library that another forum member published some time ago.  Any of these will at least reduce a considerable volume of manual key entry of code.  And they are very easy to use and understand; their learning curve is minutes rather than hours or days.

Perhaps a good incremental adoption strategy would be to try these latter tools first and then decide whether it looks as if the incremental gain from real code generation will be worth the incremental effort it requires in whatever product appeals to you most.

Welcome to .NET and CLSA.  You'll love it here once you dive in. 

Hope this helps,

 

 

PAT336 replied on Monday, August 27, 2007

Thanks Johnson.

Is there any sample win project complex than PTWin project comes with CSLA?

Patrick.Roeper replied on Monday, August 27, 2007

I know this isnt directly answering your question, but the combination code generation tools (like codesmith) and code snippets that you can write yourself will take care of the majority of these issues.

Also, I use ReSharper which makes deleting and renaming class members very clean and easy.

Last, I dont know how your authorization is setup, but we designed a data dictionary type module that bolts onto our role objects... this allows all authorization rules to be generated by the user all the way down to the property level; in essence, we never have written a single line of authorization code in any of our business objects after we had this design working correctly.

Definitely look into code generation, its one of the more appealing aspects of a framework like CSLA (at least from a production standpoint).

dmccrory replied on Monday, August 27, 2007

Patrick,

Would you be willing to share some more information about your authorization design? I am working on the same thing and would be interested in seeing how you accomplished this.

 

Thanks,

-David

stefan replied on Tuesday, August 28, 2007

Patrick,

I also would like to know more about the way you generate the authorization rules as I am currently thinking about a way of doing the same thing.

Did you decorate all properties with custom attributes?

Stefan

Patrick.Roeper replied on Tuesday, August 28, 2007

Well the design definitely isnt perfect, but it works very well with the requirements of our software solution.

First let me say that we do not use roles in the traditional sense, or at least in the way rocky did in PTracker (I think?); every user who logs into the system has a single role that they play in their organization, not a collection of roles.

Next, every customer who uses our software will always create their own set of roles; so saying "IsInRole()" will never work because the software never knows of any existing roles.

So we started off with the design that each customer will design their own unique roles for the organization (like "CPA", "HR Manager", "Guy who does all the work and makes the least", etc.) and each role is assigned an integer user level. Following this, we designed our users table so that each user was given a role that they would be assigned at login (and in essence, they have a user level now which is kept in a custom identity object on the CSLA.ApplicationContext).

CanReadProperty and CanWriteProperty were the methods that we were interested in hooking up to the user level concept; the idea was that every property of a business object should also have a read/write level and when the user is accessing the getter/setter, it should compare their role's user level to the permissions level of the corresponding property. We added some extra database tables: 1 to store a list of business objects and another to store a list of properties for each business object. On the business object table, we let the user assign CanGetObject, CanDeleteObject, ... user levels and on the properties we let the user assign Read-User Level and Write-User Level which matches up with the property level authorization in CSLA (let me just say that the default value for everything in the database is 0; in our software we look at a 0 level authorization requirement as being "no authorization required"... this lets the customer only override what they are interested in).

Obviously you dont want to make database calls everytime a user goes to access a property, so we made our own BusinessListBase<> and BusinessBase<> objects which has a static constructor; in this constructor we goto the database and fetch a list of all the property authorizations from the database and this gets cached in the business object itself (so whats happening is the first time a user loads a business object, it fetches the authorizations for that business object; the downside is that any authorization changes will not automatically reflect on a logged-in user until they logoff and logon again).

The last piece was to override CanReadProperty and CanWriteProperty in our custom business classes so that they compare the CSLA.ApplicationContext.User.Identity.UserLevel to the property authorization requirements, which at this point are cached in the business object. There is some stack tracing that goes on here but its nothing too complex. Annnddd thats it!

 

Here are the downsides that we have run into thus far:

1. There is never a clear seperation of roles in an organization to where every user has their own "level"; for example, you can have 2 people that have the same role, but one of them shouldnt be able to read a quoted prices for different jobs. We have had to create another table for overrides at the user level. This lets the customer goto a user record and explicitly say that the user can read or can write a property despite their user level.

2. The customer doesnt understand property names and business object names so in addition to the fields I mentioned above, we added a few more just to clarify the english equivalent of the business object names and property names. So in the database you have "Projects.Library.WorkOrder" as a business object name, but to the user we show "Work Order". Let me also add that we originally debated on the user's willingness to set all of this up... what we have found is that as long as the UI is intuitive, they really don't mind.

3. Keeping the database tables updated at each client site is a pain. Whenever we add 5 business objects to the software, all customer now need those to show up in their data dictionary in order to override the user levels of each. Red-Gate Data Compare has made this a lot easier.

One final note, another requirement of our software package was that the user can setup the labels associated with properties; some people say "Customer Number:" and others say "Client Number:". Since each property is now in the database, the user can override the english-equivalent of the property name (what I mentioned in #2) and this drives the label texts in the UI; 2 birds with 1 stone.

 

I hope this was helpful, I tend to ramble in any post over 2 paragraphs Big Smile [:D]

Copyright (c) Marimer LLC