- Home
- LLBLGen Pro
- Architecture
Confused with the Best Practice using LLBL
Joined: 19-Feb-2007
I am just getting my arms around LLBLGen. I've attempted to answer some of my questions by searching the forums and reading the docs, but I am still confused. Don't get me wrong, building my first business layer both in Adapter mode and in SelfServicing was easy and worked well. In addition, I have seen how to create Validation classes and even ConcurrencyPredicates to do what I want. But on the whole it looks like I am writing a lot of code in partial classes to do some of hte common practices. SO I have several questions that perhaps the readers of this forum can answer:
- Is there a way to position a wedge class without having to change the code generation (e.g. Create a class that derives from EntityBase that my business objects would then derive from).
- Do all the entity classes have to end in "Entity" (again, it seems odd that I'd need to keep my own versions of the templates to change something that simple).
- Is there a way to specify a standard CurrencyPredicateFactory to use in teh generation code without having to write code in every partial class?
Thanks in advance!
Shawn
Joined: 21-Aug-2005
The answer of all your questions is: you should modify the code-generation templates.
(again, it seems odd that I'd need to keep my own versions of the templates to change something that simple)
It's just a recommendation, and it's not a must. This is said, because you might want to revert back to the original templates, but you can skip this modification and directly modify the original templates.
Joined: 19-Feb-2007
It's just a recommendation, and it's not a must. This is said, because you might want to revert back to the original templates, but you can skip this modification and directly modify the original templates
Huh? What I am really asking is how you can make the kinds of modifications I want in the designer and not touch the templates.
Joined: 17-Aug-2003
theadoguy wrote:
I am just getting my arms around LLBLGen. I've attempted to answer some of my questions by searching the forums and reading the docs, but I am still confused. Don't get me wrong, building my first business layer both in Adapter mode and in SelfServicing was easy and worked well. In addition, I have seen how to create Validation classes and even ConcurrencyPredicates to do what I want. But on the whole it looks like I am writing a lot of code in partial classes to do some of hte common practices. SO I have several questions that perhaps the readers of this forum can answer:
- Is there a way to position a wedge class without having to change the code generation (e.g. Create a class that derives from EntityBase that my business objects would then derive from).
Yes, see the 3rd party section for v2.0. There's a set of templates which create a class which is sitting between entitybase and the generated entity classes.
- Do all the entity classes have to end in "Entity" (again, it seems odd that I'd need to keep my own versions of the templates to change something that simple).
This is planned for v2.1 to be modifyable. The suffix was added mostly to avoid having unnecessary compile errors, e.g. a 'Transaction' entity will clash with other classes called 'Transaction', even with namespaces.
- Is there a way to specify a standard CurrencyPredicateFactory to use in teh generation code without having to write code in every partial class?
You mean, one factory which is used for all entities?
In v2.1, currently in development and which is a free upgrade for v2.0 users, we'll either use an IoC / DI approach to inject the elements, or offer the options via the designer so the create methods are generated into the classes.
We currently lean towards the IoC / DI approach, as it gives less generated code and makes things more configurable.
You could try a 3rd party IoC container to inject the dependencies like validators and concurrencypredicate factories, the architecture is suitable for that.
You can also modify the entityfactory template a bit to generate the creation of the validator/concurrency predicate factory and inject them into the entities created and simply always use the factory when creating an entity.
Joined: 19-Feb-2007
Yes, see the 3rd party section for v2.0. There's a set of templates which create a class which is sitting between entitybase and the generated entity classes.
This makes sense, but if its a 3rd party set of templates it seems as though I'd lose any changes to the templates that you at SD would add. What I'd prefer is that the base class be specified in the designer and default to the right class (e.g. EntityBase). Though since I don't have a great feel for the product, I might be going down the wrong path.
This is planned for v2.1 to be modifyable. The suffix was added mostly to avoid having unnecessary compile errors, e.g. a 'Transaction' entity will clash with other classes called 'Transaction', even with namespaces.
This makes total sense. In hind-sight it seems that keeping hte ***Entity class names work well but that i'd probably create the actual subclasses that are the real objects. These classes might have the additional functionality, but would probably have to be careful to keep data that would be lost of out these classes.
You mean, one factory which is used for all entities?
I do mean one factory for all. It seems to me that in most cases I can create a factory that does the concurrency correctly for most situations. I could always write additional code for the exceptions. The big issue with how it works "out of the box" is that destructive (or non) concurrency that is used by default is just plain dangerous. I hate the fact that initially there is no concurrency management at all.
Correct me if I am wrong, but it seems though LLBL is really a database-driven version of CodeSmith with great templates out of the box. I was hoping the product would be more of a "best practices" templates that I could instruct my clients to use without having to have them modify their own templates.
I say this with some trepidation as I have a world of respect for Frans et al. And I come from the CodeGen world (I helped Chris Sells and DevelopMentor write Gen<X> which was 1/2 a decade ahead of its time).
Joined: 17-Aug-2003
theadoguy wrote:
Yes, see the 3rd party section for v2.0. There's a set of templates which create a class which is sitting between entitybase and the generated entity classes.
This makes sense, but if its a 3rd party set of templates it seems as though I'd lose any changes to the templates that you at SD would add. What I'd prefer is that the base class be specified in the designer and default to the right class (e.g. EntityBase). Though since I don't have a great feel for the product, I might be going down the wrong path.
No that's not the case. The entity code is in an include template, the template which contains the class header is pretty small and just contains constructors. That particular template is modified in that set so the generated base class is referred instead of the compiled base class.
For v2.1, the central base class approach will be a first-class citizen, with it's own preset.
This is planned for v2.1 to be modifyable. The suffix was added mostly to avoid having unnecessary compile errors, e.g. a 'Transaction' entity will clash with other classes called 'Transaction', even with namespaces.
This makes total sense. In hind-sight it seems that keeping hte ***Entity class names work well but that i'd probably create the actual subclasses that are the real objects. These classes might have the additional functionality, but would probably have to be careful to keep data that would be lost of out these classes.
The problem you then get is with hiearchies. take the dreaded example of Customer with orders. If you subclass both, you get a parallel hierarchy, because SubtypeCustomer.Orders should contain SubtypeOrder, not Order, while 'Orders' is inherited from Customer.
This isn't that bad at first, but if you bind the thing to a grid, it gets problematic, because what if Orders is empty? You then do want to have all columns of SubtypeOrder, not Order itself.
Post-generation extensibility is a painpoint every code-generation framework has to deal with. Partial classes help, however it has to be flexible enough to add all code you want to add to the partial class and not have to be a struggle. I admit we're not there yet, however it's far from hopeless:
For example, our framework offers the way to include small templates you write (so nothing modified) which are included at generation time. For example in an include template you could override the method OnInitialized, in which you create a new instance of the general Concurrencypredicatefactory you want to use and set it inside the entity.
These templates can be bound to the Custom_EntityAdapterTemplate templateid for example to include it in every adapter entity. This is then generated into the code at generation time. This template bindings file is created in template studio with a click and go interface as well as the template.
Another way to get things going is for example by enabling the task to generate validator classes. Together with that, you could add a small include template which simply overrides CreateValidator:
protected override IValidator CreateValidator()
{
return new <[CurrentEntityName]>Validator();
}
With this, after code generation, you have validator classes you can extend via partial classes (so just add the partial class with the validation logic) and they're injected at runtime automatically via the include template you wrote.
No modification of existing templates needed. Also, you just make life easier with code generation, but it's not necessary. I can also add the validator by hand or create a utility method or whatever. What we will do now is to make this step of having to write that small include template unnecessary by offering DI features. The IoC part is already implemented, as validation and concurrency management is outsourced to objects you plugin.
You mean, one factory which is used for all entities?
I do mean one factory for all. It seems to me that in most cases I can create a factory that does the concurrency correctly for most situations. I could always write additional code for the exceptions. The big issue with how it works "out of the box" is that destructive (or non) concurrency that is used by default is just plain dangerous. I hate the fact that initially there is no concurrency management at all.
There's no silver bullet concurrrency management, whatever you pick, someone will lose his/her work. Because of this, concurrency management is up to you: do you want to use timestamps, do you want to use last-value checks etc. etc. There's out of the box no concurrency management because it doesn't matter: last-save rules is just as effective as first-save rules: in both situations someone will do unnecessary work which isn't saveable. See: http://weblogs.asp.net/fbouma/archive/2003/05/24/7499.aspx
As not all entities require concurrency management, you can inject the factory you need at that given moment. This isn't automatic, admitted, but the most flexible. We're streamlining this at the moment to make the features build in much more easier to use, like enabling concurrency factories, validators and also adding auditing and authorisation.
Correct me if I am wrong, but it seems though LLBL is really a database-driven version of CodeSmith with great templates out of the box. I was hoping the product would be more of a "best practices" templates that I could instruct my clients to use without having to have them modify their own templates.
It's not about code generation, it's about entity management. The code generation part is really just customizing compiled code already there to provide you with a rich layer of functionality to manage your entity data.
You don't have to modify templates to get all the features working, as all things which are extensible are pluggable: a default DI container like spring.net could inject the validators or factories for you without a problem. To avoid people having to learn spring.net we'll add a DI solution ourselves. See the discussion here: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=8812 which is about auditing/authorisation but shows a way in which DI is usable without much effort from the developer.
I don't really see the resemblence with codesmith, as codesmith is a code genererator without a runtime library, we do use code generation but that's just a way to get code written for you.
(edit): I mentioned our runtime lib because most features provided are in the runtime lib, like prefetch paths, projections, entity views, in-memory filtering etc.
Joined: 19-Feb-2007
I don't really see the resemblence with codesmith, as codesmith is a code genererator without a runtime library, we do use code generation but that's just a way to get code written for you.
Ah, I see the light now. That makes a lot of sense.
This is a lot of great informaiton and i'll dig deeper to see how to create the validators and the base class stuff. You're certainly correct in the hierarchy mess...I often miss that problem when I start looking at this again.
Thanks again!
Joined: 17-Aug-2003
Feel free to give more feedback, the more the better . The more painpoints we get removed the better .
I did look into compile-time code weaving to get the generated code merged into your own code at compile time which could eliminate the hierarchy problem, as there is no hierarchy problem but it had some issues I couldn't eliminate at the moment, so I left it for a future version. Other people prefer having the code written out before compile time so they know what code they're using at runtime without any hidden magic. It's a tradeoff I think
Joined: 19-Feb-2007
I did look into compile-time code weaving to get the generated code merged into your own code at compile time which could eliminate the hierarchy problem, as there is no hierarchy problem but it had some issues I couldn't eliminate at the moment, so I left it for a future version. Other people prefer having the code written out before compile time so they know what code they're using at runtime without any hidden magic. It's a tradeoff I think
I am not sure we're talking about the same thing. The hierarchy of creating a wedge class to change the base class of entities (and other objects) seems obvious and shouldn't cause any hierarchy problems. But this should not need to weave it at compile or run time. The generated code would simply have the class as the derived class. It would be a class that exists at compile time (either int eh same project or as a shared class that you could reference).
Joined: 17-Aug-2003
theadoguy wrote:
I did look into compile-time code weaving to get the generated code merged into your own code at compile time which could eliminate the hierarchy problem, as there is no hierarchy problem but it had some issues I couldn't eliminate at the moment, so I left it for a future version. Other people prefer having the code written out before compile time so they know what code they're using at runtime without any hidden magic. It's a tradeoff I think
I am not sure we're talking about the same thing. The hierarchy of creating a wedge class to change the base class of entities (and other objects) seems obvious and shouldn't cause any hierarchy problems. But this should not need to weave it at compile or run time. The generated code would simply have the class as the derived class. It would be a class that exists at compile time (either int eh same project or as a shared class that you could reference).
Yes, that's what I agree with, I was more talking about the current generated entity classes code, which is now a file you have to extend via partial classes. If compile-time weaving would be implemented, you should be able to write your own classes, and the code which is now generated into the entity classes is merged with the IL of your own classes so if you want to create subtypes of all entities to work with you don't have a problem.