|
|
CSLA "Correct" Way
Last post 09-06-2008, 8:43 AM by rsbaker0. 11 replies.
-
09-03-2008, 7:38 PM |
-
Wbmstrmjb
-
-
-
Joined on 07-14-2006
-
-
Posts 39
-
Points 930
-
|
We are struggling to understand the "proper" way to implement CSLA objects in general for any typical database application. Going the ProjectTracker route of each object being whatever properties that object needs from various sources is nice, but does not lend itself to codegen. Going the route of one object per table and then combining those objects in larger objects doesn't have great performance because each object needs to make it's own database calls.
So my question is as follows. What is the normal proper CSLA way to implement the following (dumb but easy to follow) example:
Classes: Person (PersonID, Name), Car (CarID, PersonID, Make), MaintenaceRecord (MaintenanceID, CarID, StationID, ServiceDone), Station (StationID, StationName)
Relationships: Person has 0 or more cars. Cars have 0 or more MaintenaceRecords. MaintenanceRecords are for a single shop.
In a UI that shows the Person Info and Car Info with MaintenaceRecords with Station Info below, you need all 4 tables of data.
Option 1: The non-codegen way to do this would be to create a task-centric object that had the properties of the Customer and Car in it and give it a child of MaintenanceRecords collection and each MaintenanceRecord would also include the Station Info in it properties. Basically 3 objects needed, a RO PersonCar, a RO StationMaintenanceRecord, and a ROList StationMainenanceRecordList. These are all custom objects that do not work well with codegen (unless I am missing something with codegen). The SQL used to get this info needs to be custom SPs or custom join queries within the objects.
Option 2: To codegen it, we codgen all 4 tables into objects and lists for each. Now we have 8 total objects. We make a new BO that contains an instance of Station and an instance of MaintenanceRecord and call it StationMaintenanceRecord (like above). Then make a list of those StationMaintenanceRecordList (like above). We make a new BO that contains an instance of Person, and an instance of Car, and an instance of StationMaintenanceRecordList and call it PersonCar (like above). Each of the 8 lower level objects were codegened, but now a load of PersonCar take 4 seperate calls to the DB instead of one call (or maybe 2 in the case of not passing a multi-return DR down to the child).
Both options have their problems and both make certain things easier. Obviously this scenario is very basic and so codegen isn't necessary, but I am asking in the theoretical sense so that our rather large application can use whatever methodology is presented. Are we missing a third option completely that would be the best practice? Of the two I described, neither seem feasible because Rocky advocates codegen, but also would not advocate a mash up of objects that each make independent calls. So where are we going wrong?
Thanks,
Mike
|
|
-
09-03-2008, 8:02 PM |
-
sergeyb
-
-
-
Joined on 04-09-2008
-
-
Posts 361
-
Points 5,900
-
|
Mike,
You might want to look at the DeepData sample. It shows how to load data into a graph from a single stored procedure. If you want to code gen, sure you can do that. IMHO, I would code gen all the objects you listed in Option 2, then manually modify code to create a single object graph that has customer as the root. All you would need to do is add a property for each child or child list and ChildPortal access methods in your children. So, you have the best of both worlds - you code gen a bulk of code, but you modify it to be correct from business perspective. I would definitely use a single SP with multiple results sets as well.
Does this make sense?
Sergey Barskiy
Principal Consultant
office: 678.405.0687 | mobile: 404.388.1899
Magenic ®
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation
-----Original Message-----
From: Wbmstrmjb [mailto:cslanet@lhotka.net]
Sent: Wednesday, September 03, 2008 8:39 PM
To: Sergey Barskiy
Subject: [CSLA .NET] CSLA "Correct" Way
We are struggling to understand the "proper" way to implement CSLA objects in general for any typical database application. Going the ProjectTracker route of each object being whatever properties that object needs from various sources is nice, but does not lend itself to codegen. Going the route of one object per table and then combining those objects in larger objects doesn't have great performance because each object needs to make it's own database calls.
So my question is as follows. What is the normal proper CSLA way to implement the following (dumb but easy to follow) example:
Classes: Person (PersonID, Name), Car (CarID, PersonID, Make), MaintenaceRecord (MaintenanceID, CarID, StationID, ServiceDone), Station (StationID, StationName)
Relationships: Person has 0 or more cars. Cars have 0 or more MaintenaceRecords. MaintenanceRecords are for a single shop.
In a UI that shows the Person Info and Car Info with MaintenaceRecords with Station Info below, you need all 4 tables of data.
Option 1: The non-codegen way to do this would be to create a task-centric object that had the properties of the Customer and Car in it and give it a child of MaintenanceRecords collection and each MaintenanceRecord would also include the Station Info in it properties. Basically 3 objects needed, a RO PersonCar, a RO StationMaintenanceRecord, and a ROList StationMainenanceRecordList. These are all custom objects that do not work well with codegen (unless I am missing something with codegen). The SQL used to get this info needs to be custom SPs or custom join queries within the objects.
Option 2: To codegen it, we codgen all 4 tables into objects and lists for each. Now we have 8 total objects. We make a new BO that contains an instance of Station and an instance of MaintenanceRecord and call it StationMaintenanceRecord (like above). Then make a list of those StationMaintenanceRecordList (like above). We make a new BO that contains an instance of Person, and an instance of Car, and an instance of StationMaintenanceRecordList and call it PersonCar (like above). Each of the 8 lower level objects were codegened, but now a load of PersonCar take 4 seperate calls to the DB instead of one call (or maybe 2 in the case of not passing a multi-return DR down to the child).
Both options have their problems and both make certain things easier. Obviously this scenario is very basic and so codegen isn't necessary, but I am asking in the theoretical sense so that our rather large application can use whatever methodology is presented. Are we missing a third option completely that would be the best practice? Of the two I described, neither seem feasible because Rocky advocates codegen, but also would not advocate a mash up of objects that each make independent calls. So where are we going wrong?
Thanks,
Mike
|
|
-
09-03-2008, 8:07 PM |
-
rsbaker0
-
-
-
Joined on 10-12-2007
-
-
Posts 292
-
Points 4,580
-
|
Wbmstrmjb:...Going the route of one object per table and then combining those objects in larger objects doesn't have great performance because each object needs to make it's own database calls....
I too am interested in this discussion, but this is the route we have taken and so far it is performing much better than the implementation it is replacing. I have concerns though, and we have made extensive use of "lazy loading" to avoid loading child objects unless they will actually be used.
From my experience in this forum, there seems to be strong support for tailoring the object design to match the exact way they are used (e.g. the "use case"), with it being fine -- even preferable from a performance standpoint -- to have multiple objects mapped to the same database table. However, I don't see how that lends itself to code generation unless there is some intermediate design tool I'm not familiar with.
|
|
-
09-03-2008, 8:24 PM |
-
tmg4340
-
-
-
Joined on 07-10-2007
-
-
Posts 154
-
Points 2,655
-
|
This has been discussed a couple of times in other threads.
Code generation cannot necessarily develop all your classes. However, it can often be used for generating the majority of your classes - those maintenance-type screens where the use case pretty much matches the database table structure. Code generation helps get these more mundane screens out of the way, leaving you time to work on the more interesting sections.
Code generation can also help for the more interesting sections as well. Often times, code generation can develop a majority of the class structure. It won't be a 100% solution, but depending on how closely the use case matches the table structure, it can get you a long ways towards 100% - and it's boilerplate code you didn't have to write. ![Smile [:)]](/emoticons/emotion-1.gif)
HTH
- Scott
|
|
-
09-03-2008, 8:42 PM |
-
Q Johnson
-
-
-
Joined on 05-08-2006
-
Round Rock, TX
-
Posts 125
-
Points 2,050
-
|
Wbmstrmjb:...However, I don't see how that lends itself to code generation unless there is some intermediate design tool I'm not familiar with.
Maybe that "intermediate design tool" you mention here is just a code gen template waiting to be built.
I just want to offer for your consideration that the degree to which a solution's architecture "lends itself to code generation" is probably as dependent on how much YOU lend yourself to code generation as it is on other factors.
Using templates produced by others (ala CSLAGEN or other template providers of other code generation products) to generate the CSLA classes is a great start. It certainly makes you more productive than if you wrote them by hand. But there are other opportunities for applying it that are limited only by your imagination and willingness to write templates.
Give some thought to letting it do even more for you.
Good luck!
Q Johnson
|
|
-
-
-
-
09-05-2008, 6:04 AM |
-
rsbaker0
-
-
-
Joined on 10-12-2007
-
-
Posts 292
-
Points 4,580
-
|
Speaking of inheritance...
This is something of a side-issue, but you'll also get great flexibility by not deriving directly from the CSLA data object classes themselves but instead inserting a common base class between your generated classes and the intended CSLA base class. (specifically, your own BusinessBase, BusinessListBase, EditableRootListBase, ReadOnlyListBase, and CommandBase -derived common root classes)
|
|
-
-
-
09-06-2008, 8:43 AM |
-
rsbaker0
-
-
-
Joined on 10-12-2007
-
-
Posts 292
-
Points 4,580
-
|
^^^^^
Ours is a special case, since we are using an Object-Relational mapper for data access.
Our "middle layer" does all the data access -- using the ORM (the Wilson ORMapper in our case, but NHibernate also can be made to work).
However, here are some other things our middle layer does:
(1) Referential integrity constraint enforcement - blocks deletion where not allowed, propagates deletes where allowed, and provides for Validation rules to warn user when foreign key value doesn't exist, or when new primary key value collides with an existing object.
(2) COUNT, EXISTS, and aggregate functions (SUM, MIN, MAX) via CommandBase for all of our table-mapped objects.
(3) Logging
(4) Auditing
(5) Retrieval of database schema information so we can enforce maximum field length (again via business rules) to match the actual back-end database size.
(and this is just a sampler...)
We have to support 3 different back-end databases (various versions of Oracle, SQL Server, and Access), so this approach might not work for everyone, but it's working very well for us so far.
Anyway, this is just to illustrate what you can do in a middle layer...
|
|
Please contact Magenic for your .NET consulting and CSLA .NET mentoring needs. |
Please consider making a donation to help support the ongoing development of CSLA .NET. Why donate?
|
|
|