- Home
- LLBLGen Pro
- Architecture
Inheritance and coupling
Joined: 22-Nov-2005
It seems like LLBL wants you to inherit from the classes it generates. Is there any reasonable way around this?
For example, is there a way to get:
EmployeeEntity /* generated */ : Entity /* my domain object */
... inverting the dependency?
Otherwise, how are you suppose to keep the business rules decoupled from the generated code?
If I simply inherit from generated classes, then am I not forever binding the core of my application to LLBL? Many might not consider this a problem, but I'd like to avoid it if possible...
Ultimately, would like to be able to utilize DIP.
Joined: 22-Nov-2005
This generated code is referenced from your BL code. I don't think that you need to inherit directly from this.
If you have a quick look at http://www.llblgen.com/pages/files/Example_Petshop_10242005.zip you can see that you don't need to inherit from the generated DAL and entities. Also have a quick look at "Concepts - N-tier development" mk:@MSITStore:C:\Program%20Files\Solutions%20Design\LLBLGen%20Pro%20Demo\LLBLGenPro.chm: concepts_ntierdevelopment.htm
IMHO you will be tied to what ever data access strategy you adopt in at least part of your code. You maybe able to model your own enities that you use in you BL and PL layers that are independent from the LLBLGen DAL & entities, then implement a mapping tier or Business logic support tier that translates between the two. But this would just introduce more overhead into your code.
Joined: 05-Aug-2005
NRu wrote:
It seems like LLBL wants you to inherit from the classes it generates. Is there any reasonable way around this?
Don't use LLBLGEN. Oh you said "reasonable". (BTW: I've had this complaint also, but it is a minor issue)
NRu wrote:
For example, is there a way to get:
EmployeeEntity /* generated */ : Entity /* my domain object */
... inverting the depencency?
You could create your own templates to do this. However, I'm not sure what the advantage would be.
NRu wrote:
Otherwise, how are you suppose to keep the business rules decoupled from the generated code?
If I simply inherit from generated classes, then am I not forever binding the core of my application to LLBL? Many might not consider this a problem, but I'd like to avoid it if possible...
You could use Partial Classes if using VS 2005.
Or, use the Adapter pattern. It is a bit more decoupled. I am hoping Frans improves on this in the next versions so we can totally seperate our business (entity) objects from the persistence services.
BOb
Joined: 05-Aug-2005
NRu wrote:
If I simply inherit from generated classes, then am I not forever binding the core of my application to LLBL? Many might not consider this a problem, but I'd like to avoid it if possible...
You could also create your own Business Layer objects and wrap the LLBLGen entities or use them like a DAL only. I think the JCL framework omar has usues this idea.
This way, you could use your objects with LLBLGEN, or NHIBERNATE or whatever just by createing a new DAO layer.
BOb
Joined: 22-Nov-2005
pilotboba wrote:
NRu wrote:
Otherwise, how are you suppose to keep the business rules decoupled from the generated code?
If I simply inherit from generated classes, then am I not forever binding the core of my application to LLBL? Many might not consider this a problem, but I'd like to avoid it if possible...
You could use Partial Classes if using VS 2005.
Or, use the Adapter pattern. It is a bit more decoupled. I am hoping Frans improves on this in the next versions so we can totally seperate our business (entity) objects from the persistence services.
BOb
Not using .NET 2.0 yet.
And even with Adapter your BL code depends on the LLBL code:
public class MyCustomerEntity : CustomerEntity
[quotenick="pilotboba"]
NRu wrote:
You could also create your own Business Layer objects and wrap the LLBLGen entities or use them like a DAL only. I think the JCL framework omar has usues this idea.
Seems like a lot of overhead to do that... but I'll take a look.
Thanks!
Joined: 17-Aug-2003
pilotboba wrote:
NRu wrote:
It seems like LLBL wants you to inherit from the classes it generates. Is there any reasonable way around this?
Don't use LLBLGEN. Oh you said "reasonable". (BTW: I've had this complaint also, but it is a minor issue)
Still, the first person who can convince me POCO is better has to come along. I haven't seen a single argument why POCO is better.
Or, use the Adapter pattern. It is a bit more decoupled. I am hoping Frans improves on this in the next versions so we can totally seperate our business (entity) objects from the persistence services.
Adapter offers true separation of the persistence services. Or you define 'persistence services' differently of course . (also, if you want this because you then can easily swap O/R mapper layers, you're mistaken. THeres no O/R mapper which shares a query language with another o/r mapper on .NET)
Joined: 17-Aug-2003
NRu wrote:
And even with Adapter your BL code depends on the LLBL code:
public class MyCustomerEntity : CustomerEntity
Yes, but why is that bad? It gives you free code you otherwise have to code yourself. Well, unless you want to do everything yourself, why bother ?
Joined: 23-Nov-2005
Otis wrote:
Still, the first person who can convince me POCO is better has to come along. I haven't seen a single argument why POCO is better.
You've built a tool that precludes POCOs. I won't presume to convice you but here are some arguments:
POCOs:
- are easily testable
- are resuable (in contexts other than LLBLGen)
- isolate business rules
- are easier to use
Joined: 23-Nov-2005
Otis wrote:
Adapter offers true separation of the persistence services. Or you define 'persistence services' differently of course . (also, if you want this because you then can easily swap O/R mapper layers, you're mistaken. THeres no O/R mapper which shares a query language with another o/r mapper on .NET)
Adapter offers seperation into different source files... that much is true. But Adapters cannot compile without the "persistence services". The dependancy on LLBLGen still exists. This is what I'd like to decouple.
Good design principles say that business rules should be seperated from the UI and Database. Much of an application's business logic lives in the object model. LLBLGen imposes itself on the object model to a large degree.
If one were to build a system using LLBLGen and, for whatever reason, decided to use a deference persisten mechanism, they'd be screwed. The core of their system would be intertwined with LLBLGen's generated code. A rewrite would likely be the cheapest outcome.
If it were possible to decouple LLBLGen from the obejct model,.... possible to add and remove LLBLGen as just another tier, that would have merit. Then, if and when it was decided to not use LLBLGen, it would just be a mtter of replacing the persistent tier. The business rules and object model would remain untouched.
Joined: 22-Nov-2005
slagyr wrote:
POCOs:
- are easily testable
Yes, I am far more concerned about testablity than being able to replace the O/R mapper tool -- which as Frans pointed out is impossible in all but the most trivial uses of O/R mappers because you become tied to the specific object query language of the tool.
The isolation/decoupling of POCOs simplifies unit testing (in the TDD sense), and reduces the need for mock objects... so I can refactor with fewer worries, leading to a much more flexible and maintainable system. ** That** is what I really want POCOs for.
Even if POCOs are not practical in this context (for various reasons incl. performance), for testability, I still want to reduce my dependency on the mapper to the minimum. This is because I want to unit test my classes (in isolation), and inheriting from generated code complicates that.
Joined: 17-Aug-2003
slagyr wrote:
Otis wrote:
Still, the first person who can convince me POCO is better has to come along. I haven't seen a single argument why POCO is better.
You've built a tool that precludes POCOs. I won't presume to convice you but here are some arguments:
POCOs:
- are easily testable
- are resuable (in contexts other than LLBLGen)
- isolate business rules
- are easier to use
Easily testable: what does this mean? Aren't you able to write code which tests code using non-POCO classes? Mind you: the non-poco classes are generated code
Reusable: Ok, but for a price
Isolate business rules: not really true, as the field/entity oriented validation rules can be set into the non-poco classes as well.
Are easier to use: I disagree. 'easier' is highly subjective and here are a couple of points why poco's are not good: - no change tracking - no graph maintenance - no databinding support - no remoting support - no webservices support - no field versioning - in large projects (>500 tables) you have to write a LOT of code.
and don't think lightly about these. For example a poco class like a 'customer' which has a simple Orders collection, and you bind that 'orders' collection to a grid. Sadly enough, the customer didn't have orders yet. Oops! no columns! (I agree that this shouldnt be happening, but it's how .NET works, and thus that's a given)
myOrder.CustomerID = someOtherValue; now myOrder.Customer is reset. myOrder.Customer = myCustomer; now myOrder.CustomerID is set as well and myOrder is added to myCustomer.Orders. With poco you can't have that.
Easier to use? I don't see how, especially because you need to do a lot more work. Serialize them to XML? Now it's 1 line of code, and everything is been taken care of: WITH change tracking, WITH support of cyclic references, something the XmlSerializer can't handle. So 'easier' is IMHO subjective
It's these things which come for free now and which you otherwise have to write by hand.
"Oh, but I don't need them". Perhaps not NOW, but what happens if your project is 1 year old and a required change requires you to use xml, databinding or whatever? Suddenly a lot of work enters the project. And it's all plumbing code, which is already there with a non-poco approach.
Unless you like writing plumbing code, I don't see why you would opt for POCO. Or perhaps it has to be because of some weird rule setup by a manager.
Joined: 17-Aug-2003
slagyr wrote:
Otis wrote:
Adapter offers true separation of the persistence services. Or you define 'persistence services' differently of course . (also, if you want this because you then can easily swap O/R mapper layers, you're mistaken. THeres no O/R mapper which shares a query language with another o/r mapper on .NET)
Adapter offers seperation into different source files... that much is true. But Adapters cannot compile without the "persistence services". The dependancy on LLBLGen still exists. This is what I'd like to decouple.
Won't happen. LLBLGen Pro is build around the field object, which isn't removable from the design.
Good design principles say that business rules should be seperated from the UI and Database. Much of an application's business logic lives in the object model. LLBLGen imposes itself on the object model to a large degree.
That's a generalization. You've 3 types of BL: - field oriented - entity oriented - multi-entity oriented
the first 2 are often placed inside entity objects (and you can do that with llblgen pro without a problem) and the 3rd is often placed in separate classes.
True, you have to work with llblgen pro objects, though I fail to see why that's a bad thing. I see it like this: - you have a lot of work to do - most of the work you have to do is plumbing code - if you could use some code to use for plumbing code you save a lot of time.
The sad thing is that in .NET databinding and remoting/webservices support code has to be inside the object as well. IF that was placable outside the object it look better, but that's sadly not the case.
If one were to build a system using LLBLGen and, for whatever reason, decided to use a deference persisten mechanism, they'd be screwed. The core of their system would be intertwined with LLBLGen's generated code. A rewrite would likely be the cheapest outcome.
You would be in a bad situation anyway, and not because you used llblgen pro objects. The main reason is: query language. THAT code is inside your own code, no matter what you use: POCO or nonpoco. The fact is, until LINQ is here, no .NET O/R mapper will have a query language / system that's compatible with another one.
I understand your concern, but it's not only related to o/r mappers. In the llblgen pro designer I once migrated from infragistics grids to janus grids. 5 dialogs. took me 3 weeks. 3. Now, it's 'just gui code' but it's an example 'lock-in' is everywhere. Nevertheless, when will you run into the situation you describe? Because it's one of the selling points of Java . "If you for whatever reason need to switch OS, no problem!".
If it were possible to decouple LLBLGen from the obejct model,.... possible to add and remove LLBLGen as just another tier, that would have merit. Then, if and when it was decided to not use LLBLGen, it would just be a mtter of replacing the persistent tier. The business rules and object model would remain untouched.
Replacing a persistence tier is in general a dream that without a unified standard query system won't happen in .NET land. Furthermore, POCO has disadvantages as well, as I described above, which cause problems as well, and they're often rooted in how .NET works in other tiers.
I do understand you though, and I thought long and hard about how to solve the problems which are related to POCO, though in the end I decided I had no choice, simply because one of the goals I wanted to reach was (and still is ) a high level of productivity with a system that takes care of a lot of the plumbing code required.
Joined: 17-Aug-2003
NRu wrote:
slagyr wrote:
POCOs:
- are easily testable
Yes, I am far more concerned about testablity than being able to replace the O/R mapper tool -- which as Frans pointed out is impossible in all but the most trivial uses of O/R mappers because you become tied to the specific object query language of the tool.
The isolation/decoupling of POCOs simplifies unit testing (in the TDD sense), and reduces the need for mock objects... so I can refactor with fewer worries, leading to a much more flexible and maintainable system. ** That** is what I really want POCOs for.
Agreed. If you work from a true TDD pov, thus first write your complete functionality in a 'virtual' system to see if it works and then replace hte elements inside it with real code, (and not the Microsoft definition haha ), it's more work, and I fully agree that it's a concern.
Even if POCOs are not practical in this context (for various reasons incl. performance), for testability, I still want to reduce my dependency on the mapper to the minimum. This is because I want to unit test my classes (in isolation), and inheriting from generated code complicates that.
True. On the other hand, generated code is in general the aspect that it is proven code. Your own 200 entity classes still have to be tested. But I agree that if you use a pure TDD approach, it's a bit of a pain as in: you can't re-use the code you already wrote for the TDD setup, you have to replace it with classes generated which in theory can cause your system NOT to work, while it did work otherwise.
Joined: 17-Aug-2003
To elaborate a bit, before people will hammer me on the head with 10 volumes of a random Fowler book:
IF I could do what I want to do with POCO I would have picked that above anything else. Though what I wanted to avoid was proxies, assembly mangling, slow change tracking and the requirement for the user to write alot of code by hand still.
For example, databinding. There are 2 types of databinding: complex (with grids) and simple (with a property of a control, like textbox.text). Complex databinding is with collections and this can be solved IF the collection implements IListSource and thus produces some kind of view object OR implements IBindingList and ITypedList. If you just want an ArrayList, you're in for a lot of fun, especially in change tracking of the list: code removes an item from the list, user clicks on row, grid crashes.
To solve this to some extend, you can create a wrapper or proxy if you will, which will perform the binding. However the problem begins when the user digs deeper into the graph (multiple bands). per band a new proxy has to be created which is pretty complex if not undoable with a wrapper which is generic. Still, it might be possible and could work.
simple databinding on the other hand works with 'Changed' events: every property in the entity has to have a propertynameChanged event which is fired when the property changes. If this isn't there, you won't see a textbox change its value if you bind the Text property to a property of a POCO entity and you change that property in code. So you need a proxy for that too.
A proxy requires you to use non-standard object instantation. So instead of simply binding myCustomer.CompanyName to a textbox' Text property, you have to instantiate a proxy and bind to that proxy. (some O/R mappers produce these proxies under the hood, but only if you request a type from the session/context. This means that if you do Customer c = new Customer(); you don't have a proxy. )
This is IMHO not that great either. It's not great because it requires non-standard ways to do things which are standard in the usage of the objects.
If people have other solutions, ideas, please step forward, I'm all ears
Joined: 05-Aug-2005
NRu wrote:
Yes, I am far more concerned about testablity than being able to replace the O/R mapper tool -- which as Frans pointed out is impossible in all but the most trivial uses of O/R mappers because you become tied to the specific object query language of the tool.
Not if your DAO (Data access objects) layer is seperated from your busines layer. Your business objects should NOT contain query/persistence code.
Joined: 22-Jun-2004
pilotboba wrote:
Not if your DAO (Data access objects) layer is seperated from your busines layer. Your business objects should NOT contain query/persistence code.
How would that work, exactly?
[Edit] By business objects do you mean objects that implement business rules?
Joined: 05-Aug-2005
Otis wrote:
To elaborate a bit, before people will hammer me on the head with 10 volumes of a random Fowler book:
If I could do what I want to do with POCO I would have picked that above anything else. Though what I wanted to avoid was proxies, assembly mangling, slow change tracking and the requirement for the user to write alot of code by hand still.
Fowler Rules! (g)
It seems some other frameworks are taking an Inversion of Dependecy/AOP type approch to these things. My understanding is these services could be "grafted" onto the POCO objects to provide all the services. For example, you could have a Memento object that does the change tracking, a transaction object that takes care of that, an audit class that takes care of audits.
I further think that the approach taken is done without reflection so there is no major performance hit.
Otis wrote:
For example, databinding. There are 2 types of databinding: complex (with grids) and simple (with a property of a control, like textbox.text). Complex databinding is with collections and this can be solved IF the collection implements IListSource and thus produces some kind of view object OR implements IBindingList and ITypedList. If you just want an ArrayList, you're in for a lot of fun, especially in change tracking of the list: code removes an item from the list, user clicks on row, grid crashes.
I would think (still learning this) that you could write a Generic collection class that implements these interfaces and the collection could contain POCOs. And, since it is "generic" you only need to write it once, but that same collection could be used for all entities.
Otis wrote:
simple databinding on the other hand works with 'Changed' events: every property in the entity has to have a propertynameChanged event which is fired when the property changes. If this isn't there, you won't see a textbox change its value if you bind the Text property to a property of a POCO entity and you change that property in code. So you need a proxy for that too.
I'm not saying this is the best way, and I might have seen this when reading about one of the many O/R mappers I have looked at. But, your tool could dynamically create a subclass of the POCO when it was requested from the data adapter (session) which implemented the Changed event on each public property? Perhaps this is what you talk about when you say "proxies".
Otis wrote:
This is IMHO not that great either. It's not great because it requires non-standard ways to do things which are standard in the usage of the objects.
Are you saying that you don't think the factory pattern is a "standard" usage.
Otis wrote:
If people have other solutions, ideas, please step forward, I'm all ears
Hmm.... ????
BOb
Joined: 17-Aug-2003
pilotboba wrote:
Otis wrote:
To elaborate a bit, before people will hammer me on the head with 10 volumes of a random Fowler book:
If I could do what I want to do with POCO I would have picked that above anything else. Though what I wanted to avoid was proxies, assembly mangling, slow change tracking and the requirement for the user to write alot of code by hand still.
It seems some other frameworks are taking an Inversion of Dependecy/AOP type approch to these things. My understanding is these services could be "grafted" onto the POCO objects to provide all the services. For example, you could have a Memento object that does the change tracking, a transaction object that takes care of that, an audit class that takes care of audits.
I further think that the approach taken is done without reflection so there is no major performance hit.
Reflection is needed for AOP in its current form. Change tracking is something which can be added at runtime, through injection of code into the properties, it just requires a lot of work. The problem is also that if you modify an object at runtime, you add obscurity to the code that's run, which can lead to very obscure bugs and that's IMHO not what should be done.
Also, change tracking should be there always, which requires you to instantiate an object through a factory. This is thus different than: CustomerEntity c = new CustomerEntity(); // alter c.
Otis wrote:
For example, databinding. There are 2 types of databinding: complex (with grids) and simple (with a property of a control, like textbox.text). Complex databinding is with collections and this can be solved IF the collection implements IListSource and thus produces some kind of view object OR implements IBindingList and ITypedList. If you just want an ArrayList, you're in for a lot of fun, especially in change tracking of the list: code removes an item from the list, user clicks on row, grid crashes.
I would think (still learning this) that you could write a Generic collection class that implements these interfaces and the collection could contain POCOs. And, since it is "generic" you only need to write it once, but that same collection could be used for all entities.
No that doesn't work, because that generic collection doesn't know how to produce properties for the contained object type if there are no instances (collection is empty).
Otis wrote:
simple databinding on the other hand works with 'Changed' events: every property in the entity has to have a propertynameChanged event which is fired when the property changes. If this isn't there, you won't see a textbox change its value if you bind the Text property to a property of a POCO entity and you change that property in code. So you need a proxy for that too.
I'm not saying this is the best way, and I might have seen this when reading about one of the many O/R mappers I have looked at. But, your tool could dynamically create a subclass of the POCO when it was requested from the data adapter (session) which implemented the Changed event on each public property? Perhaps this is what you talk about when you say "proxies".
Sure I can do that, and indeed those are proxies. You can create proxies that way to be able to trigger lazy loading for example.
The downside is that there's no difference in the code if the object you're working with is a proxy or not. So you can write code which doesn't work but it should work, and it fails because the object used is not a proxy but a real object.
Which means there's an inconsistency and inconsistency increases bugs and failures.
Otis wrote:
This is IMHO not that great either. It's not great because it requires non-standard ways to do things which are standard in the usage of the objects.
Are you saying that you don't think the factory pattern is a "standard" usage.
First of all, I avoid to talk in patterns, as the first anti-pattern everyone should know is that patterns are building blocks. THey're standard solutions to specifically defined problems, not the other way around.
A factory can be helpful, I use them too as you know, but it's not the standard way of instantiating an object. That's: Foo f = new Foo(); not: Foo f = FooFactory.Create();
although the result is the same. If users need to use a factory to create an instance you first have to explain what a factory is, while instantiating an instance should be as simple as 1 2 3.
Joined: 05-Aug-2005
JimFoye wrote:
pilotboba wrote:
Not if your DAO (Data access objects) layer is seperated from your busines layer. Your business objects should NOT contain query/persistence code.
How would that work, exactly?
[Edit] By business objects do you mean objects that implement business rules?
OK, by "Business Object" I esentially mean an object that models a real work business entity and encapsulates the data and resposibilities of that items. This is basically what LLBLGEN Calls Entity objects.
However, it would be "possible" to create your own POCO classes and create a DAO layer which uses LLBLGEN internally. This is esentially the Facade pattern. Where you are wrapping and simplifying the LLBLGEN stuff into an object that has a simpler and consistent interface.
So, essentially your DAO object (layer) would use LLBLGEN to query the database and get the returned entities, then it would populate your POCO object using the LLBLGEN.
So you have three projects in your app
Application.EntityObjects <-- llblgenerated entity objects Application.Domain <-- POCO or business objects Application.DAO <-- data access layer
So, your UI would only reference the DAO and Domain projects. Your code in the UI layer might look something like this:
Domain.Customer cust = DAO.CustomerDAO.GetCustomer("ID"); // make mods here DAO.CustomerDAO.Save(cust);
or
List<Domain.Customer> custs = DAO.CustomerDAO.GetCustomerByState("CA");
The main point that started this thread is the problem with using the LLBLGEN Entity objects in a design where you want to decouple the Entity object from the persitence layer. This is due to the fact that LLBLGEN Entity objects derive from LLBLGEN class so they are tightly coupled to LLBLGEN classes. The question is, and I think this has been discussed before, would this (creating a whole seprate POCO layer) really buy you anything?
Your DAO layer could implement an interface for each DAO which has multiple impelmentations. One implementation could be for using LLBLGEN, one for using ADO.Net with SP's.
The iBatis DAO framework provides a nice infrastructure for this.
I am actually looking at using it for our new app version that will use LLBLGEN 2.0. Of course, we are NOT going to build a whole seperate layer of POCOs. I want to use the DAO layer as a place to encapsulate the query code so there is none in the UI layer. Also, the DAO layer could be used in a web forms and/or a windows forms app, and I don't have to re-write all the query code in each UI layer.
Frans, as he has said several times, made a choice that he didn't want to use POCO objects. One main reason was for data binding. If you made a choice to use LLBLGEN then it is a choice you have to live with.
BOb
Joined: 22-Jun-2004
However, it would be "possible" to create your own POCO classes and create a DAO layer which uses LLBLGEN internally. This is esentially the Facade pattern. Where you are wrapping and simplifying the LLBLGEN stuff into an object that has a simpler and consistent interface.
So, essentially your DAO object (layer) would use LLBLGEN to query the database and get the returned entities, then it would populate your POCO object using the LLBLGEN.
So you have three projects in your app
Application.EntityObjects <-- llblgenerated entity objects Application.Domain <-- POCO or business objects Application.DAO <-- data access layer
I understand this and see the appeal of it, but I think there's a practical constraint in many cases, namely there's still only 24 hours in a day.
No matter how you fetch data from a database (SQL or ORM on top of SQL), you have to put the data somewhere. I'm not really seeing the point in spending so much time to create new classes that duplicate all the fields and methods of LLBLGenPro entities, just because the DAO layer (LLBLGenPro) fetches data directly into these entities, whereas if you do this extra work you can say that it is your code that then moves the data from these entities into a bunch of other classes.
That's if I am understanding you correctly.
"wrapping and simplifying" will mean writing a lot of code that currently the LLBGLGenPro designer generates for you. I'm not talking about persistence logic, just a place to hold all the data and create object graphs.
Joined: 05-Aug-2005
JimFoye wrote:
"wrapping and simplifying" will mean writing a lot of code that currently the LLBGLGenPro designer generates for you. I'm not talking about persistence logic, just a place to hold all the data and create object graphs.
If you go the route of using your own POCO objects, yes you are doing alot of work, for little gain.
However, no code in my DAO layer duplicates any LLBLGEN code. But, as I said, we are using the LLBLGEN entities directly. The DAO layer is where all the filter/join/fetchpath code will go exposed as simple methods.
So:
CustomerCollection customers = DAO.CustomerDAO.GetWithOrdersByState("CA");
is simpler code than:
DataAccessAdapter da = new DataAccessAdapter(sConnection); IPredicateExpression = blah blah IFetchPath = blah blah etc etc
This code is now encapsulated in the DAOs.
BOb
Joined: 22-Feb-2005
pilotboba wrote:
However, it would be "possible" to create your own POCO classes and create a DAO layer which uses LLBLGEN internally. This is esentially the Facade pattern. Where you are wrapping and simplifying the LLBLGEN stuff into an object that has a simpler and consistent interface.
So, essentially your DAO object (layer) would use LLBLGEN to query the database and get the returned entities, then it would populate your POCO object using the LLBLGEN.
So you have three projects in your app
Application.EntityObjects <-- llblgenerated entity objects Application.Domain <-- POCO or business objects Application.DAO <-- data access layer
This is exactly what we do on the project I'm currently working on. There are a few caveats to doing it this way (mostly relating to updating collections), but in general it's a mapping layer: you map each field on the LLBL side to fields on the Domain side, both for save and for fetch. You might be able to do it with reflection if you kept your domain objects consistent with the database/LLBL side (object relationships and property names). You might also be able to generate this mapping layer using LLBL.
Again, the trickiest part is when you want to update. You need to fetch your LLBL objects from the database and do comparisons for all of your collections. Then you need to determine what the difference in the collections MEANS. If something is in the LLBL collection, but isn't in the domain collection (which is being saved), does that mean it should be deleted from the database?
pilotboba wrote:
The main point that started this thread is the problem with using the LLBLGEN Entity objects in a design where you want to decouple the Entity object from the persitence layer. This is due to the fact that LLBLGEN Entity objects derive from LLBLGEN class so they are tightly coupled to LLBLGEN classes. The question is, and I think this has been discussed before, would this (creating a whole seprate POCO layer) really buy you anything?
Here's what it buys you, and our reason for doing it this way:
It allows you to abstract your data access layer completely away from your business layer and UI. It allows you to avoid vendor lock-in.
On a purely theoretical level, I do agree with the above. The fewer dependencies you can have between layers, the better. This is self-evident.
However, I have pretty much come around to completely agreeing with Frans, and that maintaining this "purist-POCO" mentality is a waste of time and effort. Practically speaking, using LLBL objects, which encapsulate almost all the functionality you would ever need from a Domain/Entity/Business/Value object, saves you countless cycles that you can spend on the core or your application, like perfecting the data model, writing business-rules, or developing the UI.
At the end of the day, you want to do more in less time. It's going to make you and your employer (or client) happier.