- Home
- LLBLGen Pro
- Architecture
Adaptor Model / Seperate DAL Layer...
Joined: 08-Apr-2004
I have to admit I am posting this in the hope that Otis answers! Having said that, it may well be of interest to others and I welcome any responses:
I am "contemplating" an architecture around LLBGenPro, in particular the adaptor code generation model. I have worked on typical 3 tiered ASP applications in the past, and was thinking down those lines for my new project.
Initially, I was going to use the code generated (adaptor code) as the DAL layer, and make use of that in the business layer. So, the business layer would have for example a method called "GetCustomerByID", and would in the code do something like this:
DataAccessAdapter adapter = new DataAccessAdapter();
CustomerEntity customer = new CustomerEntity("CHOPS");
adapter.FetchEntity(customer);
However, I realise that this means that the business layer knows about the DAL specifics. By calling "fetchentity", I am thus unable to reuse my business layer in other projects, and I fail to get my seperation/abstraction. So, with this in mind, should I create another layer below the business layer that I call the Data layer, that does what I originally thought the business layer would do? So, the business layer would call "GetCustomerID" on the data layer, and the data layer would then instantiate the "Adaptor" code and fill the entity. Is this overkill? Have I missed something?
This has me very confused, any clarification would be welcome!
Joined: 17-Aug-2003
DataAccessAdapter implements IDataAccessAdapter. You can therefore develop your business logic with that interface and not DataAccessAdapter. You then need a method which creates the DataAccessAdapter instance for you. You can keep that method in a separate class in a separate project. It can load the database specific assembly at runtime, or staticly link to it.
so instead of: DataAccessAdapter adapter = new DataAccessAdapter();
do: IDataAccessAdapter adapter = MyAdapterCreator.CreateAdapter();
Joined: 08-Apr-2004
Thanks. If I understand what you are saying, you mean that by using the interface and having a seperate function to create the specifc DataAdaptor, I can then remove this code from the bus layer, and I also get to do things like create different DataAdptors depending on the DB type, which is all good.
However, my main "issue" is that even after I do all that, I still have a business entity which has to call "LLBGen-specific" methods to get the data it needs.. I'm not trying to say this is bad, but in architecture articles I have read I often read that one of the goals of each "layer" is to encapsulate the functionality of the layer so that it can be reused if need be - the BLL should know nothing about the database etc.. But in my business layer, I am calling things like "FetchEntity", and "GetMulti", and these are all LLGBen methods on the dataadaptor, so I would be unable to "plug" my business layer into any other data layer that was not LLBGen.
I'm not saying that this is really a problem, in real life it probably will never be the case for us that we need to take a BLL and plug it into a new DLL, but the niggle is there in my mind....I am probably either over-analysing this or have missed a key point though so any re-assurances welcome
Joined: 26-Oct-2003
Hi, sorry to jump in here but I'm still working through issues like this myself and I love to read Frans' response to these types of specific architecture questions.
However, I believe the recommended way to deal with this is to have a business layer that functions as a manager for the logical processes you work with.
So, for example, while you may have set of processes that can be reffered to as "Order-related" processes, you would have an Order Manager class that provides all of the functionality and data you need to implement these processes. This Order Manager class consumes LLBL entities and exposes properties, sub-collections, and/or methods that abstract the entity that "carries" the data, i.e., LLBL
So, while you may have an LLBL-generated OrderEntity with the properties "DateOfOrder", and "Customer", you wouldn't expose that to GUI, you would create an OrderManager class with the properties "DateOfOrder" and "Customer" that set the related properties on the LLBL entities it received and/or created.
That way, if you ever needed to change data-access frameworks (heaven forbid!) you would only have to change everything below the Manager classes.
Additionally, I've thought about creating Interfaces for each entity and collection type in the LLBL and changed the templates such that each entity and collection type implemented the interface I created. Then, I could more easily port to a different solution if I so desired. However, I would think that you would have to have a strong reason to do so, i.e., a long product lifecycle, a platform LLBL doesn't target, or a strong distrust in Frans' viability . But, it would add another layer of abstraction to the system.
Also, check out this article from elsewhere in Otis' Forums o' Fun:
http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=670
Jeff...
Joined: 17-Aug-2003
IMHO It's a myth that it's possible to replace persistence layer easily. The reason for that is that there is no standard for querying for objects for example. So every time you formulate a predicate, you have to redo that with the logic of another vendor, who probably doesn't support features LLBLGen Pro does and vice versa.
I think this will change over time, when more and more O/R mapper vendors will support the same featureset and same object query language. Till that time, it's or writing some abstraction layers (but for what?) or deal with the locking for the vendor. But you also have that with other issues as well, like when you for example use a 3rd party control set for the gui.
Joined: 08-Apr-2004
Thanks guys. I'll take a read of the referenced posting, but to reply to jeffreygg, I think that what you suggest is similar to what I was mulling over also.
I am contemplating a business layer that consumes LLBGEn methods, but returns the relitively pure entities that you get from the "adaptor model". This means that the business layer is tied to the LLBGen code, but the presentation layer is only tied to the entities, which could if need be, be replaced with custom business entities.
I know this is not the same as having a "manager" class, but it kind of takes the place of the manager class (I think).
Do you have a business layer in addition to the manager classes, or are they effectively "the" business layer - I am guessing that the manager sits between the DAL and business layer methods - is that what you mean?
I also think Otis's point about there being a limit to how easy you can make it to plug in different data layers - maybe I should not worry too much about locking my business layer to LLBGEN
Apologies if this reply is slightly muddled, its the end of the week and my brain is about to expire Time for pub methinks.
Thanks again.
Matt.
Joined: 26-Oct-2003
MattWoberts wrote:
Thanks guys. I'll take a read of the referenced posting, but to reply to jeffreygg, I think that what you suggest is similar to what I was mulling over also.
I am contemplating a business layer that consumes LLBGEn methods, but returns the relitively pure entities that you get from the "adaptor model". This means that the business layer is tied to the LLBGen code, but the presentation layer is only tied to the entities, which could if need be, be replaced with custom business entities.
I know this is not the same as having a "manager" class, but it kind of takes the place of the manager class (I think).
Do you have a business layer in addition to the manager classes, or are they effectively "the" business layer - I am guessing that the manager sits between the DAL and business layer methods - is that what you mean?
I also think Otis's point about there being a limit to how easy you can make it to plug in different data layers - maybe I should not worry too much about locking my business layer to LLBGEN
Apologies if this reply is slightly muddled, its the end of the week and my brain is about to expire Time for pub methinks.
Thanks again.
Matt.
Ok, so I'm going way beyond the point my restraining order allows me to go, so, if someone wants to reign me in please do so...but trying to answer questions like this helps me so....
I believe you want to handle all "business" functions in the Manager classes as they are the point at which the user's requests get translated into business functions. They are where your validation takes place, as well, although I'm sure that's not a hard and fast rule. So, simple answer is that the Manager classes are your business layer.
The alternate route is the Domain model, wherein each entity encapsulates its own data as well as functionality, so all of the business processes you perform in the Manager classes lie in each entity. The problem with this however, is that it doesn't model the business processes very well as many/most business processes require more than one entity to work with (e.g., Order, Order Details, Product, etc within a single "Take Order" process). It really comes down to choice based on you current circumstance.
Anybody want to check me for accuracy?
Jeff...
Joined: 08-Apr-2004
Thanks for the reply. For similar reasons you articulated, we are not going the "domain model" way. I also think it gets too complicated in bigger systems this way.
Just to pick you up on a point you made earlier:
So, for example, while you may have set of processes that can be reffered to as "Order-related" processes, you would have an Order Manager class that provides all of the functionality and data you need to implement these processes. This Order Manager class consumes LLBL entities and exposes properties, sub-collections, and/or methods that abstract the entity that "carries" the data, i.e., LLBL
So, while you may have an LLBL-generated OrderEntity with the properties "DateOfOrder", and "Customer", you wouldn't expose that to GUI, you would create an OrderManager class with the properties "DateOfOrder" and "Customer" that set the related properties on the LLBL entities it received and/or created.
This is slightly confusing to me - isn't this a domain model you are suggesting? If your manager class has properties like "DateOfOrder" and contains the methods for working with the customer, then this is a OO domain model approach, right?
Assuming that "domain model" is out of the question, I am interested in what you would propose for an alternative. I see the LLBGen entity objects as sufficient for passing all the way up to the GUI - but I think you are suggesting crteating your own. Would you create your own entity objects that the business manager layer populates from LLBGen entities? Do you think there are any advantages to this - I see it as a fair bit more code for little gain, although I might have missed something.... for example I might find I have more limitations if I use the LLBGen entities that my own....
Joined: 17-Aug-2003
Think in 'ManagerObject consumes Entity objects A, B and C'. Do not think in: "ManagerA consumes A, ManagerB consumes B'.
Where A, B and C can be: Customer, Order and OrderDetails.
You can extend this to the concept of 'Manager Works on Business Object' where Business object is for example 'SalesOrder', and SalesOrder contains: Customer, Order and one or more OrderDetail objects. Those set of objects are thus aggregated in a new object, SalesOrder, and the BL managers work on that object for example.
Joined: 26-Oct-2003
Ibid.
FYI, I'm still at the point where I'm learning this stuff. Additionally, if you'd look at the current project I'm working on you'd see a nice mish-mash of architectures as my current client gave us no room for planning, and, again, I'm still in learning mode for this stuff.
However, I like to think of the Manager layer as a service, as opposed to an object that replicates the data and behavior of any specific entity. The service exposes data, true, like the domain model, however as Frans said, the chief distinction between the two models is that the Domain model is 1:1 Entity to Functionality, while Managers expose and consume multiple types of entities to provide a single service or process-set to the end-user. So Managers are 1:m Functionality to Entities - whatever entities it takes to make up a process.
Jeff...
Joined: 08-Apr-2004
Ahh, I can now see the benefits of what you are saying when you have a manager class that consumes multiple "LLBLGen entities" and manges them in an application-friendly way.
I'm at the stage when I am trying out architectures in an attempt to "fit" them to the appliaction. Out application has oodles of database tables, so this manager "layer" may well help us here.
The only thing I worry about is that the "manager class" hides the implementation of LLBGEn away from the business and layers above. This is good - because you then get the levels of abstraction and re-use that I was originally worried about. But, this also means that I can't simply pass back my LLBLGen-created EntityCollections for data binding Still, I can pass them back as DataTables perhaps, or maybe even "custom entity collections".... Decisions decisions... If you don't mind me asking, how are you passing back collections to the presentation layer?
Thanks for the responses by the way, they have been really helpful to me
Joined: 26-Oct-2003
MattWoberts wrote:
But, this also means that I can't simply pass back my LLBLGen-created EntityCollections for data binding Still, I can pass them back as DataTables perhaps, or maybe even "custom entity collections".... Decisions decisions... If you don't mind me asking, how are you passing back collections to the presentation layer?
Thanks for the responses by the way, they have been really helpful to me
I work directly on the LLBLGen collections in the Presentation Layer. Primarily this is a direct effect of the extreme schedule my client has us on. There is/was no time to do any more abstraction than I already have. However, I will say that I don't do a lot of databinding directly to the collection, preferring more to use datatables for that purpose via GetMultiAsDataTable in Self-Servicing (Adapter wasn't available when the project started) - mainly because most of my display needs do not correspond 1:1 to an Entity.
To be honest, I've debated how to deal with collections myself assuming we ever get to the point where I can properly plan what I'm working on. I think properly one would create custom collections and/or entities used for the specific situation one is in. For example, if a certain listbox/grid needed a certain set of columns (from one or more entities), one would derive a new Entity class (and related Collection class) to handle the specific situation. For example, should this class/collection be read/write or just read? Which columns are displayed and/or editable? The problem with that solution for me is that Self-Servicing doesn't serve the inheritance requiredment very well, however it is VERY easy to use - and again it was the only thing available to me in the beginning.
Hope that helps.
Jeff...
Joined: 08-Apr-2004
Thanks. It does help!
I gues the decisions I need to make now are the decisions that I would be making irrespective of the underlying data layer. I was sold on the idea of poassing back LLBL entities, but after trying it a little, I can see situations where as you said the entities don't model the processes that well. So, what I need is a business layer that makes it easy for my UI layer, and to do that, it has to provide process entities that map to the process more closely. I think therefore that what I need to experiment with is a business layer that consists of 2 things (for each process):
- A set of methods within a class that perform the key jobs (e.g. GetByID, ListAll, ListByCategory, Add, Update)
- A process-entity (created by me, not LLBGen) that contains all of the properties I need such as ID, Title etc. The process entity is returned in a call to "GetByID", and is passed back to the BLL when the UI calls "X.Update".
The alternative, which I will also consider, is to stay with the LLBL entities, and pass those back to the presentation layer as I originally stated. However, in order to create entities that more closely match the business process, I maybe need to create more "Typed Lists", or perhaps I should inherit from the LLBL generated ones, and add properties to those..
I'll keep playing! Thanks for listening!
Joined: 08-Apr-2004
Just when you thought this thread was dead...
I'm continuing on with my voyage of architectural discovery around LLBLGen...
I now understand what you were both saying about Manager classes aggregating Object A,B,C etc.. I now have 2 solutions:
-
To go down the "Microsoft influenced" route of create business components that contain only service related code, for example "GetByID", "ListBySite" and "Update". This code works with custom entities that I create to pass the data to and from the UI layer. So, if the presentation layer wants a "product" entity, it creates a new one, and passes it to BLL.GetByID(entity). This approach is not so OO, it seperates the business code from the actual data (entities), and is similar I guess to the DataAdaptor template.
-
To stay OO, and do as I think Jeff was sggesting. So, I have a business object that might map to a couple of LLBL entities, and exposes methods and properties (e.g. collections, fields from different entities), and allows me to work in a more OO way. So, if I want to get a "product" entity, I create a new object, and call BLLObject.Load(ID). This more resembles the self servicing templates. However, as I am using the data adaptor template, this becomes less possible, does it not?
I think option 1 is winning because I understand how it would work fully, and because I am more familair with DNA web applications from ASP.
I promise I'll cease the constant architecture questions soon....promise!!
Joined: 26-Oct-2003
MattWoberts wrote:
Just when you thought this thread was dead...
I'm continuing on with my voyage of architectural discovery around LLBLGen...
I now understand what you were both saying about Manager classes aggregating Object A,B,C etc.. I now have 2 solutions:
To go down the "Microsoft influenced" route of create business components that contain only service related code, for example "GetByID", "ListBySite" and "Update". This code works with custom entities that I create to pass the data to and from the UI layer. So, if the presentation layer wants a "product" entity, it creates a new one, and passes it to BLL.GetByID(entity). This approach is not so OO, it seperates the business code from the actual data (entities), and is similar I guess to the DataAdaptor template.
To stay OO, and do as I think Jeff was sggesting. So, I have a business object that might map to a couple of LLBL entities, and exposes methods and properties (e.g. collections, fields from different entities), and allows me to work in a more OO way. So, if I want to get a "product" entity, I create a new object, and call BLLObject.Load(ID). This more resembles the self servicing templates. However, as I am using the data adaptor template, this becomes less possible, does it not?
I think option 1 is winning because I understand how it would work fully, and because I am more familair with DNA web applications from ASP.
I promise I'll cease the constant architecture questions soon....promise!!
Or if you wanted to further decouple the presentation layer from the rest of your application, you could use a combination of 1 and 2 and only pass custom entities like option 1 (not LLBLGen entities) between the BL and PL using a process/manager layer like option 2. However, based on what Frans was saying, it's possible you won't get much ROI on that.
On the other thread you have with Wayne, I agree with what he is saying about "de-normalizing" the data for use in the presentation layer. However, it's not denormalization for the sake of denormalization per se, but rather attempting to mimic the process that you are patterning your manager object on. So instead of 4 different entities in use for a typical order entry application (Order, Order Details, Products, Customers, etc) each with their own business rules and logic, you have 1 (The OrderEntryManager) that exposes properties like manager.OrderID, manager.CustomerID, and collections like manager.OrderDetails, and then manager.OrderDetails(0).Product, and methods like manager.PlaceOrder, or manager.EditOrder(OrderID).
The improvements Frans has been talking about making like creating aggregate objects (that's not the terminology he uses) which allow the developer to create a custom object graph that you can treat as a single object will go a long way towards simplifying the manager model...I can't wait to see what he comes up with
Jeff...
Joined: 15-Apr-2004
Jeffreygg wrote:
The improvements Frans has been talking about making like creating aggregate objects (that's not the terminology he uses) which allow the developer to create a custom object graph that you can treat as a single object will go a long way towards simplifying the manager model...I can't wait to see what he comes up with
I'm assuming the 'span' feature will accomplish this.
I wonder what the syntax looks like?
Joined: 08-Apr-2004
Jeff, I'd be interested on your thoughts on my latest post with wayne...
Joined: 17-Aug-2003
Fishy wrote:
Jeffreygg wrote:
The improvements Frans has been talking about making like creating aggregate objects (that's not the terminology he uses) which allow the developer to create a custom object graph that you can treat as a single object will go a long way towards simplifying the manager model...I can't wait to see what he comes up with
I'm assuming the 'span' feature will accomplish this.
I wonder what the syntax looks like?
I haven't decided yet, but not something objectspaces uses. I think more like a relationcollection.
What Jeff mentions is the composition of new classes with embedded entity classes, like a sales order which contains a customer, order and orderdetails (inside order). This is planned at the end of the year, after inheritance is implemented in full.