Best practice for using the DAL

Posts   
 
    
free4all
User
Posts: 35
Joined: 12-Sep-2003
# Posted on: 23-Sep-2003 15:05:01   

I am looking at how best to use the generated DAL from LLBLGenPro in a project.
I’m interested how others are using the DAL and any suggestions for best practice from Frans. Any pointer will be much appreciated.

Should I be using the DAL direct from my GUI? Or should I have a Business Objects in between?

Should I be using the general config or the two class scenario?

Cheers

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 23-Sep-2003 15:20:16   

I think it depends on what kind of person you are. I prefer to have '*Manager' classes like 'DocumentManager' which manages document entities and all the cruft that is related to these. Others prefer to put a lot of code in the entity object itself, for example when you have an 'Order' item, it should automatically also control inventory items to make sure the inventory stays up to date.

When you are more of a 'Manager' class kinda person, you simply create a BL tier with these classes, refer to these classes from the GUI and use the DAL in these BL tier classes. When you are more of a 'enrich the entity classes' kinda person, you probably want to use the two-class scenario generator config: extend the 'Entity' classes and re-generate the '*EntityBase' classes over and over again.

You can also create a combination of both: put the low level BL code in the entity classes using the two-class scenario, and also create a BL tier with '*Manager' classes which consume the DAL classes (entity classes) and are referenced by the GUI. For example, you can extend the OrderEntity class in the two-class scenario to hold 1 extra property which calculates the total price of the order using the OrderDetailsCollection in that order object. You then can also create an 'OrderManager' class which includes code to create a full order with orderdetails and checking with a variety of other logic (for example the InventoryManager to see if an ordered product is on stock or should be backordered).

But always keep in mind: there is not 1 single way to do it. If a certain way of working with the DAL is best for you, according to you, then use it that way. For the llblgen.com site I skipped a middle tier sometimes, because it was so easy to just read a customer object in the code behind page. The more you abstract away in tiers, the more you can re-use the tiers, but it will also require more programming.

Frans Bouma | Lead developer LLBLGen Pro
free4all
User
Posts: 35
Joined: 12-Sep-2003
# Posted on: 23-Sep-2003 16:41:33   

Thanks for the quick reply Otis or is it Frans?

I am curious about the “*Manager” pattern you mentioned could you describe in a little more detail how these work and perhaps give an example?

I have database of Students with two tables PersonalDetail and Module, PersonalDetail has a 1:n relationship to Module using the PK Student.Number.

Using the “*Manager” approach how would I return a single student and their modules?

With my current setup the BL has an object called Student which is made up of the PersonalDetail entity and a Module Collection which are exposed as public properties. So to return a single student and their modules with the number “123” the GUI uses the following code:

Business.Student student = new Business.Student("123");

SurnameTextBox = student.PersonalDetails.Surname;

ModulesDataGrid.DataSource = student.Modules;

Also how would I search for and return a list of students using the “*Manager” approach?

With my current setup the Student object in the BL has a method called Search which returns a TypedView. So to find a student with the surname “SMITH” the GUI uses the following code:

Business.Student student = new Business.Student();

StudentSearchTypedView results = student.Search("SMITH");

resultsDataGrid.DataSource = results;

The main worries I have about my current approach are:

  1. Exposing the full PersonalDetails entity as a public property allowing more access to the GUI than is really needed. Is my only other alternative to expose each individual field via its own public property? (Resulting in lots of repetitive code)

  2. Returning the StudentSearchTypedView to the GUI meaning if this view changes I have to recreated through all layers. Is there anyway around this?

Sorry for the long post, I hope I’ve made myself clear. I realise there is no definitive answer to this type of question, I just don’t want to be doing something badly if there is a better way.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 24-Sep-2003 10:42:22   

free4all wrote:

Thanks for the quick reply Otis or is it Frans?

I use 'Otis' as a nick on boards etc. since my Amiga days (since 198sunglasses so I'm pretty used to being called Otis simple_smile

I am curious about the “*Manager” pattern you mentioned could you describe in a little more detail how these work and perhaps give an example?

Well, a small example would be this forum. It is build with LLBLGen 1.x, using datatables, but the BL structure is similar: it has for example a ThreadManager class. This class manages threads: when you create a new thread, add a message to a thread, edit a message in a thread etc., it is all controlled by that class. The GUI works with that class and calls methods of that class. The ThreadManager itself works with the DAL objects and processes data from the gui so things get done and processes data from the DAL for the GUI so stuff gets displayed correctly. With LLBLGen Pro you probably will move some code out of this manager type of class because it is a little overkill to instantiate a 'message' object in a BL class and pass it on to the GUI, the GUI could also instantiate the object itself.

I have database of Students with two tables PersonalDetail and Module, PersonalDetail has a 1:n relationship to Module using the PK Student.Number.

Using the “*Manager” approach how would I return a single student and their modules?

Because the generated code already works with objects, you could simply instantiate the student entity and return that to the gui. The GUI would then simply do student.Modules and get access to the modules objects. Am I correct in saying that 'PersonalData' == Student? Perhaps you should name your PersonalData entity 'Student', since it gives access to the modules via the relations.

With my current setup the BL has an object called Student which is made up of the PersonalDetail entity and a Module Collection which are exposed as public properties. So to return a single student and their modules with the number “123” the GUI uses the following code:

Business.Student student = new Business.Student("123"); SurnameTextBox = student.PersonalDetails.Surname; ModulesDataGrid.DataSource = student.Modules;

Also how would I search for and return a list of students using the “*Manager” approach?

You simply implement a method 'Search(searchfield)' on the manager class which internally would construct a predicateexpression, execute a GetMulti() with it and return the entity collection to the caller. The GUI can then work with a single method, and how the search is performed is abstracted away, that's the purpose of the BL class: when something changes in the BL class, the GUI will keep on working.

With my current setup the Student object in the BL has a method called Search which returns a TypedView. So to find a student with the surname “SMITH” the GUI uses the following code:

Business.Student student = new Business.Student(); StudentSearchTypedView results = student.Search("SMITH"); resultsDataGrid.DataSource = results;

The main worries I have about my current approach are:

  1. Exposing the full PersonalDetails entity as a public property allowing more access to the GUI than is really needed. Is my only other alternative to expose each individual field via its own public property? (Resulting in lots of repetitive code)

No. When you use the two class scenario, you can override each property in the entity class, because they are virtual. This means you can for example add a new implementation (overriding the original in the PersonalDetailsEntityBase class) and add a browsable attribute with the value 'false'. It will then not show up in your datagrid. (it will on the web, because the datagrid for asp.net is crappy. Check out the code in EntityBase in the ORM support classes sourcecode how to exclude properties in grids). You can also add whatever code you like to the PersonalDetailsEntity class, for example overriding UpdateEntity(), with extra logic, so the gui will not be able to call save.

  1. Returning the StudentSearchTypedView to the GUI meaning if this view changes I have to recreated through all layers. Is there anyway around this?

When the view changes, for example the columns change, you have to regenerate the code, however you don't have to change anything else, if you just bind it to a grid.

Sorry for the long post, I hope I’ve made myself clear. I realise there is no definitive answer to this type of question, I just don’t want to be doing something badly if there is a better way.

Since there is no 'good' or 'bad', it's hard to do it really bad simple_smile . Keep focussing on the functionality you have to implement. That's key. Then, try to create a list of priorities about the code, like 'it has to be using tiers which absolute abstract interfaces' or 'I don't want to instantiate anything in the GUI'.. then, act according to that priority list and write the code. Don't be afraid to make mistakes, we all do, myself included (every day wink ). Sometimes, after a project is done, the list of priorities was not totally right, and looking back you probably will think 'I should have done this differently...', however because a lot of ways lead to the same goal: implementing the functionality that has to be implemented/realized, it will not matter much for the finished project, it will matter for your next project: you will be able to create the list of priorities based on a more mature set of skills and knowledge.

Frans Bouma | Lead developer LLBLGen Pro
free4all
User
Posts: 35
Joined: 12-Sep-2003
# Posted on: 24-Sep-2003 12:46:53   

I use 'Otis' as a nick on boards etc. since my Amiga days (since 198sunglasses so I'm pretty used to being called Otis simple_smile

Ok Otis is fine by me. simple_smile

Well, a small example would be this forum. It is build with LLBLGen 1.x, using datatables, but the BL structure is similar: it has for example a ThreadManager class. This class manages threads: when you create a new thread, add a message to a thread, edit a message in a thread etc., it is all controlled by that class. The GUI works with that class and calls methods of that class. The ThreadManager itself works with the DAL objects and processes data from the gui so things get done and processes data from the DAL for the GUI so stuff gets displayed correctly. With LLBLGen Pro you probably will move some code out of this manager type of class because it is a little overkill to instantiate a 'message' object in a BL class and pass it on to the GUI, the GUI could also instantiate the object itself.

Thanks for the example I'm pretty sure I understand the theory now.

I have database of Students with two tables PersonalDetail and Module, PersonalDetail has a 1:n relationship to Module using the PK Student.Number.

Using the “*Manager” approach how would I return a single student and their modules?

Because the generated code already works with objects, you could simply instantiate the student entity and return that to the gui. The GUI would then simply do student.Modules and get access to the modules objects. Am I correct in saying that 'PersonalData' == Student? Perhaps you should name your PersonalData entity 'Student', since it gives access to the modules via the relations.

Yes I see your point, because the DAL is returning me a single object which has the related modules I only need to return the Student entity. flushed

The reason I have 'PersonalData' was before using LLBLGen Pro 'PersonalData' and 'Modules' where two separate unrelated objects being joined together by the parent Student object. Student.Student would have looked a little strange so I decided on Student.PersonalData.

With my current setup the BL has an object called Student which is made up of the PersonalDetail entity and a Module Collection which are exposed as public properties. So to return a single student and their modules with the number “123” the GUI uses the following code:

Business.Student student = new Business.Student("123"); SurnameTextBox = student.PersonalDetails.Surname; ModulesDataGrid.DataSource = student.Modules;

Also how would I search for and return a list of students using the “*Manager” approach?

You simply implement a method 'Search(searchfield)' on the manager class which internally would construct a predicateexpression, execute a GetMulti() with it and return the entity collection to the caller. The GUI can then work with a single method, and how the search is performed is abstracted away, that's the purpose of the BL class: when something changes in the BL class, the GUI will keep on working.

Yes that sounds fine to me I guess my only worry is returning a collection object which could then be used by the GUI to modify the data without going through the BL. To be honest its not really a big issue as most projects are a currently a one man effort and I would know to always use the BL. But sometimes I work in a small team and there is the potential for other developers to use the DAL directly skipping the BL abstraction.

With my current setup the Student object in the BL has a method called Search which returns a TypedView. So to find a student with the surname “SMITH” the GUI uses the following code:

Business.Student student = new Business.Student(); StudentSearchTypedView results = student.Search("SMITH"); resultsDataGrid.DataSource = results;

The main worries I have about my current approach are:

  1. Exposing the full PersonalDetails entity as a public property allowing more access to the GUI than is really needed. Is my only other alternative to expose each individual field via its own public property? (Resulting in lots of repetitive code)

No. When you use the two class scenario, you can override each property in the entity class, because they are virtual. This means you can for example add a new implementation (overriding the original in the PersonalDetailsEntityBase class) and add a browsable attribute with the value 'false'. It will then not show up in your datagrid. (it will on the web, because the datagrid for asp.net is crappy. Check out the code in EntityBase in the ORM support classes sourcecode how to exclude properties in grids). You can also add whatever code you like to the PersonalDetailsEntityBase class, for example overriding UpdateEntity(), with extra logic, so the gui will not be able to call save.

Yes I understand what you are saying, I guess I was looking for an EASY way to return from my BL a Student entity which is read only so the GUI could not mess around with it. When is say EASY I mean me not writing any or very little code. wink

  1. Returning the StudentSearchTypedView to the GUI meaning if this view changes I have to recreated through all layers. Is there anyway around this?

When the view changes, for example the columns change, you have to regenerate the code, however you don't have to change anything else, if you just bind it to a grid.

Yes very true again my mistake and lack of understanding of your product.

Sorry for the long post, I hope I’ve made myself clear. I realise there is no definitive answer to this type of question, I just don’t want to be doing something badly if there is a better way.

Since there is no 'good' or 'bad', it's hard to do it really bad simple_smile . Keep focussing on the functionality you have to implement. That's key. Then, try to create a list of priorities about the code, like 'it has to be using tiers which absolute abstract interfaces' or 'I don't want to instantiate anything in the GUI'.. then, act according to that priority list and write the code. Don't be afraid to make mistakes, we all do, myself included (every day wink ). Sometimes, after a project is done, the list of priorities was not totally right, and looking back you probably will think 'I should have done this differently...', however because a lot of ways lead to the same goal: implementing the functionality that has to be implemented/realized, it will not matter much for the finished project, it will matter for your next project: you will be able to create the list of priorities based on a more mature set of skills and knowledge.

Yes I often go back to code and think did I really do that! I am currently reviewing my first project with LLBLGen Pro hence all the questions. I don’t think I have done the project badly, the users are delighted with the product and thanks to LLBLGen Pro they got it within a very tight deadline. Before starting another project and without the deadline hanging over me I have time to review what I have done and ask myself (and others) is there a better way?

I am happy with the answers you have supplied which are really outside the scope of ‘support’ for your product and I thank you for that. Now if I can only find an EASY way to get read only entities/collections...

I look forward to the SDK being released and maybe hassling you some more! wink

Cheers

Gabor
User
Posts: 97
Joined: 29-Jan-2005
# Posted on: 01-Feb-2005 10:42:50   

Frans,

You can also add whatever code you like to the PersonalDetailsEntityBase class, for example overriding UpdateEntity(), with extra logic, so the gui will not be able to call save.

Apologize for the newbie question, we habe to overwrite PersonalDetailsEntityBase or PersonalDetailsEntity class?

If we override the update method, how we can save this entity in the BL in two class scenario?

Thanks

Gabor

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 01-Feb-2005 11:19:13   

Gabor wrote:

Frans,

You can also add whatever code you like to the PersonalDetailsEntityBase class, for example overriding UpdateEntity(), with extra logic, so the gui will not be able to call save.

Apologize for the newbie question, we habe to overwrite PersonalDetailsEntityBase or PersonalDetailsEntity class?

If we override the update method, how we can save this entity in the BL in two class scenario?

My mistake, you should override UpdateEntity() in PersonalDetailsEntity, which calls base.UpdateEntity() if some condition is met. (override the one with the restriction). This way, calling Save() on a non-dirty entity will always end up in your own UpdateEntity() routine.

Add that method to the class created for you in the 2-class scenario. However if you want to add concurrency checks, also take a look at implementing IConcurrencyPredicateFactory which can produce retrictions for saves at runtime for you.

I'll edit my post above to undo the mistake simple_smile

Frans Bouma | Lead developer LLBLGen Pro