- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Evaluating LLBLGen Pro - Questions
Joined: 21-Apr-2011
Hello,
I am using 3.1 Final - TRIAL, April 14th, 2011. I develop (and generate) Visual Basic code.
I am evaluating LLBLGen Pro for possible use in a project. I have read the documentation up to the Concepts section in the documentation for the designer and for the runtime framework.
I am currently studying the "Using the generated code section" of the runtime framework documentation and now have a few questions.
-
In a project's properties, I have set the EntityBaseClassNameDefault property to something other than the default, "CommonEntityBase". No matter what I set it to, the generated code names the entity base class "CommonEntityBase", instead of using the name I typed in.
-
Private variables used in generated entities are prefixed with an underscore; "_entityName". I prefer my private variable naming convention, which is "m_EntityName". How do I ensure that the generated code follows my convention?
-
Private variables and arguments are generated as lower camel case; "Public Sub New(equipmentId As System.Int32). My naming convention stipulates upper camel case and that integer primary keys be suffixed with a capital "I" and a capital "D"; "Public Sub New(ByVal EquipmentID As System.Int32)". How do I ensure that both these rules are enforced in generated code?
-
Generated arguments are structured without the ByVal operator; "Public Sub New(equipmentId As System.Int32)". My convention stipulates very strict explicitness; "Public Sub New(ByVal EquipmentID As System.Int32)". How do I ensure that arguments in include the ByVal operator?
-
Generated entities are named with the suffix "Entity"; "EquipmentEntity". My naming convention calls for only the entity name; "Equipment". How do I ensure that entity names use my convention?
-
Similarly, generated collection classes use the suffix "Collection". My naming convention calls for the suffix "List". How do I ensure that the names of each of the entity types use my conventions?
-
I am unsure the order in which I should be doing things in the designer. For example, nothing in the designer, other than by experimentation, informs me that I need to 'Add Relational Model Data from a Database...' (when using a data-driven approach, of course), then to 'Reverse-engineer Tables to Entity Definitions' by right-clicking on the catalog name. I suppose I will reach a point in the documention where these steps are described, but I'd like the interface to provide the basic steps needed to follow the methodology the user wishes to employ. Does the interface provide this guidance?
Thank you, Shep Houston, TX
P.S. I have been reading forum posts all day. I have found partial answers to a couple of my questions.
Regarding question no. 1 above, I find further that the generated entities (with the entirely unnecessary 'Entity' suffix attached) do indeed inherit from whatever I typed in for the 'EntityBaseClassNameDefault' property. However, the 'CommonEntityBase' filename remains 'CommonEntityBase.vb' and the class name within this file remains 'CommonEntityBase'; "Public MustInherit Class CommonEntityBase".
This is clearly a bug.
P.S. Further testing on no. 1 above: If I type in something other than the default for the 'EntityBaseClassNameDefault', then build the project, 102 errors are introduced. I suppose this number is mostly dependent upon how many entities I'm generating. Editing the solution to replace my chosen base class name with 'CommonEntityBase' fixes all 102 errors.
Is this also a bug in the non-trial release of 3.1?
Also, I read the page which describes the template system in LLBLGen Pro and left confused. Where exactly do I edit the templates? I note there are 46 templates bound to 'SD.TemplateBindings.SharedTemplates.NET20.templatebindings'. Am I to expect that, if I need to correct the naming oddities I find in LLBLGen generated code, that I will have to modify a good portion of those 46 files?
Thanks again. Still testing...
Joined: 08-Oct-2008
Let's start with your PS first - it's not a bug. CommonEntityBase is generated as a base class regardless of whether any of your generated Enity classes will inherit from it or not - it's just part of the LLBLGen framework. If you do change the "EntityBaseClassNameDefault" to another class name then you need to create this class for your self, and ensure that it inherits from the framework's base class for entities EntityBase (self servicing) or EntityBase2 (adapter)
I'll address your other points in a second. As a general thought though, does it really matter what the generated code looks like, or how it is formatted...? 99% of the time you will never need to look at it, and it should never need to be manually modified. You could even compile it straight after generation, and just use a binary reference.
With that in mind... Points 2-6 : ALL of the code generation in LLBLGen is template driven. The templates are plain text files which are installed in folders under the main program installation, and can all be manually modified by the end user. They can be opened and edited in the LLBLGen designer, which will also give you syntax highlighting. All of your points in 2-6 would require changes to the templates - the designer does give you some control over the names of certain generated elements, but down to the level of detail you require.
There are some caveats though. Bear in mind that if you do make wholesale changes to the templates it makes it very difficult to upgrade to newer versions of LLBLGen. This is why I was so keen to stress above the fact that generated code does not match your coding standard might not be the end of the world
Point 7 - the designer does not give you any real indication or walk through of the process that you need to go through, it really is something that you need to work out for yourself from documentation and experimentation. Having said that, it's generally a fairly short simple process, and once you've been through it a few times it becomes fairly slick.
Matt
Joined: 21-Apr-2011
Thanks Matt, I appreciate the discussion.
I understand better the methodology you describe re: the CommonEntityBase file and how it fits into the framework. However, the name of the property 'EntityBaseClassNameDefault' indicates to me that it is a 'default', and that whatever I set it to will be the 'default' base class name. It is more than a little confusing, and I still view it as a bug, but I accept your explanation.
Points 2-7: I understand and thank you for your explanation.
Finally, in answer to your question, "does it really matter what the generated code looks like, or how it is formatted?", my answer is...
YES. Absolutely, Yes. It matters, greatly. I start with a complete database and generate only once, and use the generated code in my project. I do not place that code into a separate assembly and reference it. When minor changes occur in the backend I simply refactor the affected entity or entities.
Even if I were to do as you suggest (compile the generated code and reference the assembly), I still demand highly readable code which matches my (or a project manager's) conventions and standards.
Sorry, but in my opinion, your response is like that of a piano tuner I hired, who failed to correctly tune one key near the far end of the keyboard. When I pointed it out, he asked, "How often do you really play at that end of the keyboard?"
Needless to say, he was not called again.
Seriously, if I didn't care what the generated code looked like, then I wouldn't need an option to select C# vs. VB output, would I?
Which begs the question - why is there an option to select the output language in LLBLGen Pro?
Thanks, Shep
Hi Shep,
I understand your concerns. For Question 1 you have a point, and we will investigate it.
For the rest of the questions I think the recurrent requirement is: "I want the generated code follow my code conventions". I can start a debate about code conventions or best practices, etc., but instead, if you really want to, you can modify templates to meet your requirements. For that you will need to read the SKD documentation. LLBLGen is a top-notch OR/M tool and it has years of improvements. So please think about modifying 3rd party generated code conventions, think about all your 3rd party software you use. If LLBLGen ever let people inject their own conventions in code, the generated code would be another story (think about it). Said that, you can still do whatever you want because LLBLGen is very flexible: you can modify the templates, write your own templates, put additional interfaces, namespaces, attributes to every element, etc, write your own plugins, debug the ORMSupportClasses source code, write a new framework settings file, etc.
We are very glad that you are evaluating the tool, but keep in mind that the generated code is not your code, it's a specialist data access layer generated code that do the plumbing work for you and somethings are done that way because is the best way.
Shep wrote:
- In a project's properties, I have set the EntityBaseClassNameDefault property to something other than the default, "CommonEntityBase". No matter what I set it to, the generated code names the entity base class "CommonEntityBase", instead of using the name I typed in.
We'll look into it.
- Private variables used in generated entities are prefixed with an underscore; "_entityName". I prefer my private variable naming convention, which is "m_EntityName". How do I ensure that the generated code follows my convention?
That can't be done. We follow MS' guidelines.
- Private variables and arguments are generated as lower camel case; "Public Sub New(equipmentId As System.Int32). My naming convention stipulates upper camel case and that integer primary keys be suffixed with a capital "I" and a capital "D"; "Public Sub New(ByVal EquipmentID As System.Int32)". How do I ensure that both these rules are enforced in generated code?
The 'D' can be done using a setting in the project properties, which has effect after you've re-created the entities again: MakeElementNamePascalCasing and EnforcePascalCasingAlways
the uppercase first character can't be configured.
- Generated arguments are structured without the ByVal operator; "Public Sub New(equipmentId As System.Int32)". My convention stipulates very strict explicitness; "Public Sub New(ByVal EquipmentID As System.Int32)". How do I ensure that arguments in include the ByVal operator?
That's unnecessary, the default is ByVal in VB.NET
- Generated entities are named with the suffix "Entity"; "EquipmentEntity". My naming convention calls for only the entity name; "Equipment". How do I ensure that entity names use my convention?
You can't configure that. As you're using VB.NET, you should be happy about this actually, as the VB.NET compiler often has a problem to distinguish between property name and type name. The suffix is meant to avoid problems during compilation due to name clashes with existing types and property names. (And before you wonder "that's not really necessary", yes it is. )
- Similarly, generated collection classes use the suffix "Collection". My naming convention calls for the suffix "List". How do I ensure that the names of each of the entity types use my conventions?
You can't.
Regarding question no. 1 above, I find further that the generated entities (with the entirely unnecessary 'Entity' suffix attached) do indeed inherit from whatever I typed in for the 'EntityBaseClassNameDefault' property. However, the 'CommonEntityBase' filename remains 'CommonEntityBase.vb' and the class name within this file remains 'CommonEntityBase'; "Public MustInherit Class CommonEntityBase".
This is clearly a bug.
It might be. Anyway, I don't know what you're planning on changing there, but it's actually of little value to change that. Our framework relies on all entities having a base class in our runtime. CommonEntityBase is a generated class which inherits from that base class and all entity classes inherit from that class. This way, you can add custom code to all the generated entities by adding a partial class of CommonEntityBase to the generated code project. If you want to inherit from something else, that other class has to inherit from our base class. So in other words: what you're likely planning to do isn't going to work.
YES. Absolutely, Yes. It matters, greatly. I start with a complete database and generate only once, and use the generated code in my project. I do not place that code into a separate assembly and reference it. When minor changes occur in the backend I simply refactor the affected entity or entities.
LLBLGen Pro was released first in 2003, we're doing this for a long long time. How the code is constructed is a result of many years of little changes and tweaks. If you drastically change from that, you're bending the framework to your work, instead of bending the work to the framework. For example, the generated code is in a separate assembly because you shouldn't add all your code in that project, but in another one.
You also shouldn't refactor the generated code. When changes happen in the DB, you refresh and regenerate. Not only is that faster, it's also solid, as we've thought about how to change things for you.
Even if I were to do as you suggest (compile the generated code and reference the assembly), I still demand highly readable code which matches my (or a project manager's) conventions and standards.
We follow MS' guidelines. Your standards don't match that, so that means we have to make every little thing configurable to meet some standard, as every developer might have a different standard. We obviously can't do that, also because it's actually irrelevant: the code is compiled, used in your application.
Sorry, but in my opinion, your response is like that of a piano tuner I hired, who failed to correctly tune one key near the far end of the keyboard. When I pointed it out, he asked, "How often do you really play at that end of the keyboard?"
Needless to say, he was not called again.
Sorry but I fail to see the analogy between your piano tuner and us and our generated code.
Seriously, if I didn't care what the generated code looked like, then I wouldn't need an option to select C# vs. VB output, would I?
Frankly, if it was our choice we wouldn't generate VB.NET at all (see below why we are supporting VB.NET and what we've done for that (i.e. a lot)). But some customers want VB.NET code, so we generate it. Another reason we do it is: it is an advantage if you want to extend the generated code with partial classes. In that case you need to write the extensions in the same language as the generated code, so if that generated code is VB.NET, you'd be able to write the extensions in VB.NET as well.
I can't reproduce it. (the base class name)
When I change in the project properties the default to CommonEntityBaseChanged, I can see the name is changed when I open an entity in the editor and go to code gen. info tab, I see the EntityBaseClassName property set to 'CommonEntityBaseChanged'.
When I generate code, the entity classes (VB.NET or C#, doesn't matter) all inherit from CommonEntityBaseChanged, which of course doesn't exist. I think you misunderstood the reason this setting is there. I'll try to explain:
The idea behind this setting is this: If you don't want all entities to inherit from CommonEntityBase, but instead from another class which derives from CommonEntityBase or directly from EntityBase (or if you're using adapter, EntityBase2), you can specify it there in that setting.
So the setting isn't for specifying the name of the 'CommonEntityBase' class that's generated. All entities inherit from CommonEntityBase by default. If you want to add common code to a lot of entities, you can add it to a partial class to CommonEntityBase (so that's a new file, added to the generated code project). However as all entities inherit from CommonEntityBase, all entities will get that code. if you want some entities to not have that code, you can by adding a new class to the generated code, similar to CommonEntityBase, and specify that class name as the base class for the entity / entities which shouldn't get the common code you added with a partial class to CommonEntityBase, and you do that in the code gen. info tab in the entity editor for these entities.
Additionally, if you want to use another class as base class for the entities, which directly inherits from EntityBase/EntityBase2, you can as well, by specifying it as the default in the project properties.
If you then don't want the generated CommonEntityBase (but I really fail to see why you wouldn't want it... it's already there, use it ), you can switch off the task in the preset in the code generation configuration dialog which pops up when you generate code: on tab 3 disable SD.Tasks.SelfServicing.CommonBaseClassGenerator (if you're using selfservicing).
Joined: 21-Apr-2011
Ok Otis, thanks for the detailed response. I do appreciate it.
I think many others will benefit from this discussion as well, especially when they take note of your comment,
"Frankly, if it was our choice we wouldn't generate VB.NET at all."
That pretty much says it all right there. If I'd known you folks were stuck-up curly brace types, I wouldn't even have downloaded the trial.
I'll be looking to your competition to spend my money. Thanks.
Shep
Shep wrote:
Ok Otis, thanks for the detailed response. I do appreciate it.
I think many others will benefit from this discussion as well, especially when they take note of your comment,
"Frankly, if it was our choice we wouldn't generate VB.NET at all."
That pretty much says it all right there. If I'd known you folks were stuck-up curly brace types, I wouldn't even have downloaded the trial.
I'll be looking to your competition to spend my money. Thanks.
Shep
err Shep, just because we like C# more than VB.NET doesn't mean we don't support VB.NET in every shape or form. Our linq provider for example has a lot of VB.NET specific code to make it work for VB.NET originating expression trees. Only EF/Linq2Sql have that too. Another example is the way we generate VB.NET FluentNHibernate code, where we generate extra methods to overcome a VB.NET limitation. We do support VB.NET in every way, and when we say that, we mean it. All our documentation examples have VB.NET code, and when needed, we explain VB.NET specific things, like the lack of namespaces in the VB.NET vs.net projects before .net 3.5. All our features are supported on VB.NET as well as C# and the generated code for VB.NET has all features found in the code generated for C#, and we'll continue to do so as long as customers ask for it (and till this day, they do, so we'll continue with 100% supporting VB.NET).
I made that remark to show you that we do listen to our customers when they request for things. That you have demands we can't meet isn't a result of that we like C# more than VB.NET, but a result of the demands being unrealistic (and your idea of how to use the tool doesn't fit with how the tool is design to), at least in our eyes. We can't make our generated code meet every coding standard possible, as that amount is literally endless. Your demands also aren't vb.net specific, they're your idea of how to write software specific. That's OK, the thing is that if you want us to emit e.g. names of method arguments in pascal casing, we need to change that everywhere, and it doesn't give a single bit of extra value. It's generated code, not code you would change manually: all arguments of methods in the .NET framework are also camel cased, I'm sure you aren't asking MS to change that too, do you? .
But alas, if you think we won't help you because we are stuck-up curly brace types, so be it Let me say that the competition is in most cases even less VB.NET friendly, so I'm not entirely sure you'll find what you're looking for elsewhere, but I wish you good luck