10 Tips for Entity Framework Reverse POCO Generator
The POCO generator creates fast entities through it's T4 generation. Today, we show some interesting tips on using this extension to it's maximum potential.
T4 (Text Templating Transformation Toolkit) has been around for a long time (since Visual Studio 2005), but didn't gain any traction until Visual Studio 2008/2010.
The idea behind T4 was to use code to write code, but no one knew about it until in later versions when a .tt file started appearing in solution files.
Yes, Visual Studio has a custom code generator built into it! To see how T4 works, I'll refer you to an older post titled 5 Ways To Take Your ASP.NET MVC Development to "Ludicrous Speed".
The best part about T4 was seeing the various templates people were using to generate C#, SQL, CSV files, and anything else code related using T4.
When Entity Framework arrived, someone decided to build a T4 template to scaffold Entity Framework code off of a database.
Enter the Entity Framework Reverse POCO Generator.
The Entity Framework Reverse POCO Generator has been around for a long time and has become a required extension in my toolkit.
The Reverse POCO Generator is a T4 template packaged as a Visual Studio extension allowing you to scaffold Entity Framework elements based on an existing database. It generates code such as DbContexts, entities, unit testable Fakes, stored procedures, and views just to name a few.
There are a couple of reasons I like this approach:
- The T4 is considered "source code" even though it's a code generator. You can easily version the .tt file by checking it into version control.
- If the database was modified, load the T4 template, press Ctrl-S to save/regenerate code, and it automatically regenerates your entities based on the changes in the database.
- While examining the template, you'll see it has a number of comments on how to adjust the T4 to suit your needs. VERY flexible.
- With all of the flags and modifications, if you don't like the generated code, you can modify it.
However, some comments don't explain some of the other features in this template.
So today, I wanted to review some of the tips I've learned over the years on using the full potential of this T4 generator. This post examines version 2.36.1.
One quick note: the extension does not support .NET Core or other databases (PostgreSQL, Oracle, MySQL, etc.).
No Config File? No Problem
Sometimes you don't have a config file (app or web.config) handy.
In this case, it's easier to just include the connection string in the T4 template.
- Comment out line 9 (Settings.ConnectionStringName = "blah")
- Uncomment lines 13-14
- Settings.ConnectionString = "<connection string>";
- Settings.ProviderName = "System.Data.SqlClient";
Press Ctrl-S to save your changes.
See Things Clearer with a T4 Editor
Trust me. Viewing T4 code can make your eyes cross.
The best thing to do is get a T4 Editor with syntax coloring.
Here are some possibilities for Visual Studio:
- If you have Resharper, you can install an extension called ForTea
- DevArt has a nice extension called T4 Editor and it's free.
- tangibleEngineering also has one called tangible T4 Editor (notice a pattern here?) ;-)
Once installed, you'll see things a little clearer.
Don't Keep 'Em Separated
While it's great to view each individual class and DbContext by itself, keeping everything together makes things a little easier in the long run.
- Line 24, keep Settings.GenerateSeparateFiles to false
The reasoning for this lies in the next tip.
Use Partial Classes
If you are in a Domain Design Development (DDD) mood, it'll make more sense to use partial classes so your POCOs are pure.
- On line 26, change Settings.MakeClassesPartial to true
Once you save this template, all of your Entity Framework classes will regenerate and contain a partial keyword added to the class.
Why is this good? Two reasons:
- With partial classes, BOTH partial classes are required to reside in the same namespace.
- As I mentioned in the previous tip, if you separate your entities into their own files, you can't easily add a partial class with the same name in same folder without stepping on the generated code.
You want to work AROUND the generated code as much as possible. So if you hit Ctrl-S, you won't lose any code changes.
NEVER touch the generated code.
...Or Keep 'Em Separated
(I know, I know. I have the same song in MY head as well).
If you absolutely need to separate them, check out lines 113-133.
- Lines 113-116 defines what you want to generate (Elements.Poco, Elements.Context, Elements.UnitOfWork, or Elements.PocoConfiguration)
- Lines 118-133 tells you where to place them in your project.
For example, if you want your POCOs placed in a Classes folder, line 130 would look like:
Settings.PocoNamespace = "YourProject.Classes";
So you can place your mapping code into a EFMapping folder, UnitOfWork and Context in a DbContext folder, and your POCOs in your Entities folder.
Every time you save your T4 template, it would generate the classes in their appropriate folder.
Just Fake It
By default, the template generates a Fake<YourDbContext> and Fake<DbSet<type>>.
- Lines 45 - Confirm Settings.AddUnitTestingDbContext is set to true
This allows you to easily build your own in-memory database. If you want to quickly populate an in-memory database to assist with your testing, check out my post on The Fastest Way To Mock A Database For Unit Testing.
Do You Have A Relationship?
With Entity Framework, a many-to-many relationship is hard to map, but if your tables are setup properly, it should generate the code.
Even though this strictly deals with Entity Framework, I've seen this go wrong a number of times where devs are wondering where their navigation properties disappeared to.
Let's look at a student/classes/studentclasses table structure where studentclasses is the junction/associative table.
- In SQL Server Management Studio, open the table design for studentclasses
- In your design, you should have ONLY two fields: studentId and classId. This lets Entity Framework know it's a junction table.
- Use Ctrl-Click to select both fields and make both Primary Keys
- Right-click in the left-hand column and select the "Relationships..." menu option.
- Add a studentclasses->studentId relationship that points to the student->studentId table.
- Add a studentclasses->classId relationship that points to the classes->classId table.
- Save your Changes
When your entities are generated, you'll notice you won't see a StudentClasses class anywhere. Based on your table definitions and relationships, it isn't necessary.
Entity Framework is smart enough to know a relationship exists between these two entities and acts on it accordingly with navigation properties in the form of collections.
Filter, Filter, Filter
In the T4 template, you don't have to generate the kitchen sink.
You can generate only tables beginning with "REF_" or stored procedures in a particular schema.
The filtering is formatted as follows:
- For simple, bulk include/exclude filtering, Settings.<type>FilterInclude or Settings<type>FilterExclude can use a RegEx.
- For more granular approaches, the Settings.<type>Filter is an expression to use a more specific table name or stored procedure.
These filters for tables and stored procedures are throughout the template:
- Lines 164-168 is for the large-scale filtering for schemas, tables, and columns with Settings.SchemaFilterExclude, Settings.SchemaFilterInclude, Settings.TableFilterExclude, Settings.TableFilterInclude, and Settings.ColumnFilterExclude
- Lines 170-180 is meant for filtering tables at a more granular level with the Settings.TableFilter.
- Lines 183-186 is the Stored Procedure FilterInclude/Exclude
- Lines 188-198 is the Stored Procedure Filter to loop through all sprocs to determine which ones to generate
I know generating the code doesn't take any extra time, but I've used the filtering to save myself the hassle of generating a ton of entities and stored procedures.
Schema Use
Using a database with a schema can cause problems when generating code, but not with the POCO generator.
- Line 140 allows you to prepend the schema name on to your entities and other classes. I personally can't stand this option, so I set Settings.PrependSchemaName to false;
- Based on the filtering mentioned above, you can examine a table or a stored procedure using the Filter Expression to determine whether to use it or not based on the schema.
A while ago, there was a single setting for pulling tables based on a simple schema name. It seems that was removed to make way for the Filter expression way of processing entities/tables.
Nullable? Yes. No. Maybe?
It seems there was a recent addition to the template in regards to nulls.
- Line 43 has a Settings.NullableShortHand set to true
This comes in handy when you want to use the latest C# Nullable types using a question mark as opposed to the Nullable<type>.
If it's true, it will generate "T?". If false, it will generate "Nullable<T>"
Conclusion
This post just scratched the surface as to how many options there are in this template.
Any time I need to create an EF application with an existing database, I reach for this extension. There are a ton of ways to customize the code.
If you want even more of a deep dive into this extension, check out the Pluralsight course called Code-First Entity Framework with Legacy Databases.
Have you used every single option in this template? What feature do you like the most? Post your comments below and let's discuss!