Why use T4 to modify entities in EF? - entity-framework

What is a valid reason for using the 'ADO.NET EntityObject Generator' with EF? In case you don't know, it generates a T4 file that does the building of the entities from the edmx. You can then change the T4 file to change how the entities are generated.
My question is: other than changing the base class in which entities are derived (also implementing interfaces) and changing the accessibility of entities and/or the context objects and naming conventions, what use does this have? Considering the existing features of EF and partial classes.
I've come up with 2
Grab the table/column descriptions from the database and populate the summary on the entities and properties
Generate light wieght DTO's and do auto mapping.
1 seems like too much work considering it only updates the comments on the models, not the edmx itself (although it could do so)
2 Is this even useful?

We have done a few things with the T4 templates. The first one is to split out the generated code into one class per file, instead of one massive file. This just makes it easier to navigate and browse through the entities.
The second, and more important one, is to automatically generate data annotation validation attributes such as StringLength and Required. This lets us validate our entities with a single function call, and it makes sure that their validation attributes are always in sync with the database (since if we change a column length in the DB, for example, the generated StringLength() attribute is then updated when we do 'Update model from database').
At a previous job, we also added base classes and interfaces to the entities, as you mentioned in your question.
Here's a snippet from our T4 template that checks for required columns and string lengths and adds the necessary validation attributes:
''' <summary>
''' <#=SummaryComment(primitiveProperty)#>
''' </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
<EdmScalarPropertyAttribute(EntityKeyProperty:=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable:=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)>
<DataMemberAttribute()>
<#+
' begin required attribute
If Not ef.IsNullable(primitiveProperty) and not ef.IsKey(primitiveProperty) then
#>
<#+
If ef.ClrType(primitiveProperty.TypeUsage) = GetType(Guid) Then
#>
<GuidRequiredAttribute(ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> is required")>
<#+
Else
#>
<RequiredAttribute(ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> is required")>
<#+
End If
#>
<#+
End If
If HasMaxLength(primitiveProperty.TypeUsage) then
Dim d = MaxLength(primitiveProperty.TypeUsage)
#>
<StringLengthAttribute(<#=d#>, ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> cannot be longer than <#=d#> characters")>
<#+
End If
#>

Well, the reason is that you can do anything with it. So, why don't have it? Of course the usage of T4 is very limited to some special cases, and most of the time it doesn't make sense to use it. On the other hand you can do funky stuff with it. For example you can define some user defined stuff. Let's say you have a Sort column in your table. Then you could define a query function where it automatically sorts every entry if this column exists. Maybe too trivial for an example, but there are tons of other weird architectures where it makes much more sense.
You can also make use of other code generation stuff, without EF. So it's certainly here for completeness and extendability.

T4 template replaces custom tool used in EFv1 to generate code behind file (.designer.cs file with all classes). The main advantage of T4 is that you can change it per project just by modifying text .tt file. In case of custom tool changes were mostly impossible.
With T4 you have complete control over entity classes generated from your EDMX. It is transformation of EDMX into C# or VB.NET files. The default template creates class files with features required by most of developers but if you need anything else you can simply go to your .tt file and add it.
Possibilities for changes are unlimited because EDMX file itself is extensible. On behind EDMX is just XML file and you can include your own custom XML elements in this file (it has some restrictions but it is possible - here is some example for SQL generation in model first approach). Once you have custom elements in EDMX you can use them in T4 template as decision logic for additional features you want to include in generated code. Entity designer is also extensible - you can create custom extensions which will be stored as custom elements in EDMX file. Both EDMX and Entity designer extensions are nicely described in book Entity Framework in Action.

I know this is an old question, but I would have liked to come across this information when I started out.
In our case where we have a win32 Delphi client in our multi-tier solution, I've used the templates (in C#) to generate the DTO classes in .Net, and the win32 counterparts.
This allows us to encapsulate the CRUD functionality on the client using largely auto-generated Delphi code:
procedure Delete;
class function DeleteDto(const _dESPATCHID: integer) : boolean;
class function GetNextID : integer;
class function Get(const _dESPATCHID: integer) : TDtoDESPATCH; overload;
class function Collection(const __filterXml: string): TList<TDtoDESPATCH>;
function Load: boolean; overload;
function Populate(_primaryDict : TDictionary<string, Variant>) : boolean;
function Save : boolean; overload;
Change tracking from the client can also be automated, so each property setter will mark the changed property, to ensure only changed properties are updated.
For example:
procedure TDtoDESPATCH.SetSCT_STATUS(const value : string);
begin
if (self.IsLoaded) and (inherited SCT_STATUS <> value) then
begin
TrackChange('SCT_STATUS');
self.Modified:= True;
end;
inherited SCT_STATUS := value;
end;
On the server side, another template takes care of all the CRUD operations in an auto-generated WCF service that's also exposed as an asmx web service. The Interface, WCF methods and all annotations are generated from the template.
// convert to entity
var _entity = _dto.ToEntity();
if(exists)
{
Global.LogActivity(string.Format("{0} - profile {1}, updating DESPATCH: {2}", racID, profile, _dto.ChangedProperties ));
// Attach the entity to the db
db.DESPATCHes.Attach(_entity);
// Change tracking
ChangeTracking<DESPATCH>(_dto.ModifiedProperties, db, _entity);
}
In a scenario where WIN32 has to be part of the solution, hand coding all this would be a (worse) nightmare.

I've used them quite a bit to generate code that is useful to us at a Datalayer level.
Altering whether they implement additional contracts (interfaces), adding methods, annotations and in the case of a non-layered application (and NOT recommended beyond this) adding property changed notification.
By adding some of these items to the generation at the Datalayer, I've been able to use a template in the Model project to generate the boiler plate code at this level too.
Bottom line, if you can safely get the computer to code for you, then it's well worth while. In our case 80% of basic plumbing work can be code genned - if it's incorrect, it's generally very easy to fix and regenerate.

Related

Auto=RTrim Strings in Entity Framework, ServiceStack OrmLite, PetaPoco, etc

Edited for Clarity
I've been looking at ORMs for the last week, as well as trying to decide if I want to bother with them. At the end of the day, there seem to be about a dozen worthy contenders, of which most are fairly hard to tell apart. I eventually settled on the potential trio of EF, OrmLite and PetaPoco, all of which seem pretty good.
One feature I've been looking for is the ability to magically configure the code generator to automatically right trim all strings in the generated POCOs, without any changes to the DB. I have a database with literally thousands of records spread across hundreds of fields, and every single string field has a bunch of spaces at the end of it for legacy reasons. Those need to be stripped from the resulting POCOS/Entities to make the processing less ugly, but I can't make any changes to the DB (it's not mine), so I'm wondering if there is easy-easy way to do it.
With Entity Framework I looked a little bit at the process for Database First and Model First design, and those look like you could probably tweak the T4 template code to generate appropriate code on a case by case basis. This seems like it would be viable, but I don't want to reinvent the wheel if someone has already done it. I would just like to have the code that takes care of the problem.
For the other ORMs, I could probably pull them in the house, figure out how they work and plug-in some kind of logic that does the magic.
So does anybody have a suggestion for an ORM that has a configuration switch that can automatically right-trim all strings? It would make the database much easier to work with, hundred percent certain there is never any value in those extra spaces at the end.
Thought this was a good feature so I've just added this to ServiceStack.OrmLite where you can now add a custom filter for strings, e.g:
OrmLiteConfig.StringFilter = s => s.TrimEnd();
public class Poco
{
public string Name { get; set; }
}
using (var db = OpenDbConnection())
{
db.DropAndCreateTable<Poco>();
db.Insert(new Poco { Name = "Value with trailing " });
var row = db.Select<Poco>().First();
Assert.That(row.Name, Is.EqualTo("Value with trailing"));
}
It will be in the next v4.0.19+ NuGet release of ServiceStack, which is now available on ServiceStack's MyGet Feed.
With Entity Framework (and possibly PetaPoco which I don't know personally) you should be able to modify the T4 template and add read-only properties to your entities, returning the trimmed value of database-related property.
public string Name
{
get { return this.DbName.TrimEnd(); }
}
But...
You have to find a way to do this for string properties only (I think one of the methods that are visible in the T4 template can be used for that, but I'm not sure).
Modifying T4 templates is something you may have to do again when updates are released.
You can't use the read-only properties directly in LINQ-to-entities because EF can't translate them into SQL. You'll alway have to use them after an AsEnumerable() call.

EF naming, is there a setting to change all field names to lower case?

When use EF with breezejs, seems server side should have each name starts with upper case, and on client side, use camel style, like
FirstName on EF and
firstName on client side.
I think it is not as good as all lower case, everyone can understand firstname, not necessary FirstName or firstName.
I wonder if it is strongly suggested to not use all lower case name? If I want to use all lower case name, is there a way to tell EF (database first) to create class with all lower case name no matter what they are on the db side?
Thanks
I think you should do this within your JSON serialization and deserialization. If you're using Web API you can do this. From OdeToCode:
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
If you don't want to do this with your JSON serialization, then if you're using EF6 code first you can do some custom conventions to achieve this for your column names. Do something similar for tables.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Properties()
.Configure(p => p.HasColumnName(p.ClrPropertyInfo.Name.ToLower()));
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new UserHashHistoryConfiguration());
}
See this post on MSDN for more information on custom conventions in EF6.
This is what the Breeze NamingConvention is for.
See: http://www.breezejs.com/documentation/naming-convention
But you may have a problem because the NamingConvention needs to be able to roundtrip your name. i.e. passing from server name to client name and back to server name needs to get back to the original name. With your rule there is no way to get from an all lowercase name back to the original server name unless you are willing to keep a map of all previously mapped names or come up with some other heuristic.
The example below demonstrates the issue.
var lowerCaseNamingConvention = new breeze.NamingConvention({
serverPropertyNameToClient: function (serverPropertyName, prop) {
return serverPropertyName.toLowerCase();
}
clientPropertyNameToServer: function (clientPropertyName, prop) {
// need to get back to original name here
return clientPropertyName. ???
}
});
lowerCaseNamingConvention.setAsDefault();
I'm not clear on why you want to change the property names on the server-side. Property names in .NET classes are expected to be PascalCase.
You're free to do as you please and name the properties as you wish in the EF mapper. It's harder to do in EF Database First; you can use the designer to map each property name exactly as you want to see it but wow is that time consuming. There are advanced techniques with T4 that might be better if your model is huge (beware: you can spend more time writing/debuggin T4 than just slogging through and mapping the property names by hand).
If you were willing to go with Code First, you could take a look at EF 6 custom conventions which appear to be sufficiently flexible and powerful.
You DO realize that this is not a breeze question, right? The Breeze NamingConvention (mentioned by others) is the proper place to make your client-side properties look the way you want them to look.
There isn't always a way to calculate the transform; sometimes you just have to provide a dictionary in your NamingConvention.
However, you seem to want to handle this by remaking the classes on the server. That (as you've noted) is harder and/or tedious. There is nothing Breeze can do about that.
p.s.: using JSON.NET configuration to try to cope with this during serialization will not work. You want property names that you can reference in queries and JSON.NET does nothing to morph the property names mentioned in query strings.

Mogenerator and setPrimitiveType

I have about a half dozen tables coming from a legacy web server. These tables all have a "type" column. I need to keep these column names in sync at the app level.
Using mogenerator, the base class it creates dutifully generates a setPrimitiveType attribute. Well Apple doesn't like this method and rejected our app.
Is it possible to change mogenerator to not create certain methods of the model's attributes?
Yes, it is possible to fine-tune what mogenerator creates. This is done by updating the entries in the templates for the machine files. For example, the following lines can be commented out from the machine.h template file.
- (void)setPrimitive<$Attribute.name.initialCapitalString$>:(<$Attribute.objectAttributeType$>)value;
- (void)setPrimitive<$Attribute.name.initialCapitalString$>Value:(<$Attribute.scalarAttributeType$>)value_;
The former is the regular accessor. The latter is the scalar accessor and it could even be renamed if desired.
However, do notice that the Core Data framework and not mogenerator are generating the basic accessors as pointed out by the Apple Docs Core Data Programming Guide:
For example, given an entity with an attribute firstName, Core Data automatically generates firstName, setFirstName:, primitiveFirstName, and setPrimitiveFirstName:. Core Data does this even for entities represented by NSManagedObject. To suppress compiler warnings when you invoke these methods, you should use the Objective-C 2.0 declared properties feature, as described in “Declaration.”
I had the same problem with 'type' keyword.
My solution was manually creating and implementing methods like
- (NSNumber *)primitiveType;
- (void)setPrimitiveType:(NSNumber *)value_;

CA: Suppress results from generated code not working in VS2010 beta 2

I'm trying to run codeanalysis on an assembly that contains an entity model (edmx file). In project properties I have checked the "Suppress results from generated code" option, but I am still getting a lot of CA errors pertaining to the auto-generated EF code.
Has anyone experienced this? And is there a work-around?
Just put the attribute on your class definition.
But how to do it, since your file can get overridden any time. Use a separate file, since all generated classes are partial classes. Open a separate file, and write something like:
[GeneratedCode("EntityModelCodeGenerator", "4.0.0.0")]
public partial class YourEntitiesContextName : ObjectContext
{
}
This will skip code analysis on your particular generated class. StyleCop for instance is more smart and doesn't touch files that have .designer/.generated part in their name or regions that have generated word in their name.
Well, "Suppress results from generated code" really means "Don't look at types with GeneratedCodeAttribute". EF's code generator hasn't added this, historically (though I've suggested it to the team). But you can add it if you use custom T4.

Resolving associated objects in SL4 RIA

Having created a standard Silverlight Business Application in VS2010 and set up a model from a SQL Server database, I have various entities and associations, among which AssetGroup and Asset are in a 1:m relationship.
Allegedly I can use dot notation to get the associated AssetGroup out of an asset instance. Through the modern miracles of deferred execution and lazy loading, I am assured, my data will be delivered the very moment that I need it.
But it doesn't work.
What are the required incantations, and do I have to slay a chicken or a goat?
This looks promising. As soon as I've tried it out I'll update.
In the question I mention a blog post containing a possible solution. That solution works, but entails changes to generated code, which is obviously as fragile as a solution gets.
Here's a robust way to apply the solution: change the code generator.
On the EDMX designer surface right-click for the context menu and choose Add Code Generation Items...
Try to improve on "Model1.tt" as a name and save the TT file.
Open the TT file.
Search for "return (" to directly find the method template you need to change.
Edit as shown.
Rebuild the solution.
Change this
return /* big hairy expression */;
to this
var entity = /* big hairy expression */;
if (!entity.IsLoaded) entity.Load();
return entity;