- Home
- LLBLGen Pro
- Architecture
Business Layers, Inheritance and Collections
Joined: 17-Feb-2005
Hello All,
Been thinking about this one quitea bit, and I can't think of an easy solution. I'm hoping that I'm too close to the problem and a fresh set of eyes will see something obvious.
First some background:
i) We are redeveloping our core application from the ground up, so no legacy code. ii) We are in the Microsoft Whidby early adopter program and one of the great benefits that I see is that there is the ability to bind UI controls to objects/collections, so I want our object model to be used from top to bottom in our application. iii) I've been doing some proof of concept work using the Self Servicing model, as that's quicker and easier. iv) I have a very basic knowledge of LLBLGen Pro v) We are moving from a mix of VB6 C++ and ASP to C# and ASP.NET vi) Final applications will be web sites, desktop apps, mobile devices, client server, intranet and web services.
Now for an example of my problem, this is a "made up" example to make it simple so please ignore the daft "business logic".
We have Groups which have a collection of child Groups (and a parent Group) and all Groups can also have a collection of Accounts
The Account entity needs some functionality, e.g. some complex validation needs to be passed before saving is allowed
Now I can inherit from Account to, for example, My_Account and add the validation in there, but, finally here is my real question, how do I ensure that only My_Account is only ever used?
How do I make My_Account available to someone traversing the object model?
I don't want to add this to the DAL as I would like to cleanly seperate the Business logic from the data access logic
The obvious answer is to inherit from Group to My_Group and override the Accounts collection creation, but the problem is that there are multiple paths throught the object model which might end up acccessing an Account entity.
I think what I would like to do is to create a Facade through which I would only expose the required methods and properties and change the templates so that all generated code has protected access, but in this thread http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=2259 it is suggested that this is not a sensible thing to do.
In summary I want users of the business layer to only to be able to access my inherited classes, and to be positively denied access to the underlying generated classes.
Am I missing anything obvious? Is this just a stupid idea?
Thanks.
Ian Fraser
Joined: 17-Aug-2003
bigwave wrote:
In summary I want users of the business layer to only to be able to access my inherited classes, and to be positively denied access to the underlying generated classes.
Am I missing anything obvious? Is this just a stupid idea?
It's not stupid, it's a bit problematic to implement. The point with inheritance is that you can always cast to the parent type. That doesn't mean it will hurt. Here's a basic example:
public class A
{
public virtual void Foo()
{
Console.WriteLine("A.Foo");
}
}
public class B:A
{
public override void Foo()
{
Console.WriteLine("B.Foo");
}
}
//... somewhere in code:
B b = new B();
b.Foo();
A a = (A)b;
a.Foo();
will give: B.Foo B.Foo
So even if they cast to the original entity class, your overriden methods will be called. I'd opt for Adapter in your case too, which disallows any code other than the business tier to call persistence logic. This is important in your case. With adapter, the GUI tiers only have access to the entity code, not the adapter code, as that project isn't used in the GUI and not referenced. This means it has to call the BL tier for everything: fetching data, saving data etc. The BL tier can then inject the right entity validator object and validate the entity and throw exceptions for example.
Joined: 17-Feb-2005
Otis wrote:
bigwave wrote:
In summary I want users of the business layer to only to be able to access my inherited classes, and to be positively denied access to the underlying generated classes.
Am I missing anything obvious? Is this just a stupid idea?
It's not stupid, it's a bit problematic to implement. The point with inheritance is that you can always cast to the parent type. That doesn't mean it will hurt.
<snip>
So even if they cast to the original entity class, your overriden methods will be called.
<snip>
My concern is that I (or more likely another programmer) would
i) Have an instance of an inherited entity, to use my example, My_Account
ii) They would "go up" to the Group that owns it
iii) Iterate through the collection of Accounts via the LLBL generated collection
iv) They would be accessing the generated Account entities, not my, inherited, My_Account entities
v) Thinking about it they would also be accessing an LLBL Group entity in (ii) and not my, inherited, My_Group entity.
So they wouldn't be casting to the original entity they would have direct access to the original entities.
Does my explanation of this make sense?
Joined: 17-Aug-2003
bigwave wrote:
Otis wrote:
bigwave wrote:
In summary I want users of the business layer to only to be able to access my inherited classes, and to be positively denied access to the underlying generated classes.
Am I missing anything obvious? Is this just a stupid idea?
It's not stupid, it's a bit problematic to implement. The point with inheritance is that you can always cast to the parent type. That doesn't mean it will hurt.
<snip>
So even if they cast to the original entity class, your overriden methods will be called.
<snip>
My concern is that I (or more likely another programmer) would
i) Have an instance of an inherited entity, to use my example, My_Account
ii) They would "go up" to the Group that owns it
iii) Iterate through the collection of Accounts via the LLBL generated collection
iv) They would be accessing the generated Account entities, not my, inherited, My_Account entities
v) Thinking about it they would also be accessing an LLBL Group entity in (ii) and not my, inherited, My_Group entity.
So they wouldn't be casting to the original entity they would have direct access to the original entities.
Does my explanation of this make sense?
If you use the derived entity templates for adapter, entity collection references in entities hold entities of the derived types, not the base types. So going up to a parent group, will bring them to the derived entity of a group, holding your derived entity (myaccount).
Joined: 17-Feb-2005
OK, I'm not sure that I've explained myself clearly.
Time for some ASCII art.
----------------------------
| Application level DAL (3) |
----------------------------
|
| Other Assembly
|--------------------------
| DAL Assembly
|
V---------
| FACADE |<- Inherits from DAL (2) with selected
--------- <- "public" methods, properties, etc.
|
V-------------------------------
| DAL (2) Customisable classes |<- includes code for data integrity/security
-------------------------------- <- All classes etc. are "protected"
|
V----------------------
| DAL (1) Base Classes | <- All classes etc. are "protected"
-----------------------
So the Application level DAL can inherit from the Facade (I'm not sure if this is actually the correct term) and make use of collections of entities, etc, but only the ones that we decide to make public in the Facade.
This way we could stop anyone accidentally accessing the low level functionality that we don't want exposed (e.g. security should be transparent) and simplify coding at the application level (as only the methods/properties we need are exposed)
The important point I'm trying to get across is that we want to expose the object model (collections/relationsships/etc) but not all of it (to simplify the interface between the DAL and the, many, applicatoins that will use it).
Is this a clearer explanatoin of what we are trying to achieve?
Ian Fraser
Joined: 17-Aug-2003
If you want to block access to methods in classes in dal 1 or 2, you shouldn't expose the class through the facade directly, but aggregate it into another class, OR make sure the methods you don't want to expose are overriden with methods which make sure the code in dal 2 is executed and not code in dal 1 (like I tried to explain with my inheritance example).
Though, if you place an adapter in dal2, and special methods in the facade (like GetCustomer(id) ), you'll never be able to call a random adapter method in the application layer, you have to access the facade for that. And because an entity by itself is not somethng you can save without an adapter (which isn't available in the application layer) your dal2 functionality is guaranteed.