Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Entity Validation and the Entity Framework – Part 1

DZone's Guide to

Entity Validation and the Entity Framework – Part 1

· DevOps Zone
Free Resource

Download “The DevOps Journey - From Waterfall to Continuous Delivery” to learn learn about the importance of integrating automated testing into the DevOps workflow, brought to you in partnership with Sauce Labs.

Introduction

The next logical step in my journey across the Entity Framework v6 RC1 after having established a fairly robust data access approach was to imbue my solution with some more “smarts” when it came to entity validation.

Out-of-the-box Entity Framework POCO entities are exactly as advertised – plain old CLR objects – and, as such, do not contain any inherent validation hints or help.

There are a plethora of validation approaches available, including extending the entity classes with partial classes, but I wanted something implemented which would be core to the data access approach – and (because I’m lazy) something that didn’t require any hand written code, outside of modifying a template.  After all, the EDMX already knows about nullable fields and field lengths, right?  Why not take advantage of that knowledge?

To be clear – this is not an approach designed to validate entities in an interactive fashion as there are other approaches which would work better, including UI validation.  Instead, this is an implementation designed to catch (and reject) any inserts or updates which would genuinely fail if an attempt to commit the changes was made – i.e. this is a last ditch sanity check.

Interrogating the T4 template

To accomplish what I want to do, you’ll have to be comfortable hand editing the T4 template which is used to generate the Entity Framework POCO entities.  If you haven’t done a lot of templating before, this might seem a bit daunting at first.

Untitled_thumb[2]

If you expand the <DataModel>.edmx file, you’ll see there are a host of linked dependency files.  The one we’re interested in specifically is called Model.tt and it is a direct dependency of the EDMX file itself.

There’s a fairly obvious format to the template, and you can actually play with the template and see the results.  Every time you save the template it triggers the templating engine – but be warned, any errors will break the template and you’ll get an error message.

An Example Schema Object

Let’s look at an example from my previous data schema.  As you can see, nothing terribly scary here, but there are a couple of required fields (not-nullable) and some fields which have defined lengths (we’re focusing on strings here).

image_thumb5

What I’m aiming to produce are some Data Annotations decorating the appropriate properties on my corresponding Catalog data entity, which would look like this (apologies for the text wrapping):

// Simple Properties

[Required(ErrorMessage="[Property 'CatalogId' in entity 'Catalog' is a required property.]")]
public int CatalogId { get; set; }
        
[StringLength(100, ErrorMessage="[The field 'Title' in entity 'Catalog' cannot be longer than 100 characters.]")]
[Required(ErrorMessage="[Property 'Title' in entity 'Catalog' is a required property.]")]
public string Title { get; set; }
        
[StringLength(400, ErrorMessage="[The field 'Description' in entity 'Catalog' cannot be longer than 400 characters.]")]
public string Description { get; set; }

public Nullable<System.DateTime> DateTaken { get; set; }
        
[StringLength(50, ErrorMessage="[The field 'OriginalFilename' in entity 'Catalog' cannot be longer than 50 characters.]")]
public string OriginalFilename { get; set; }

public Nullable<int> Orientation { get; set; }

// End Simple Properties

To accomplish this I also need the class implementation to use the following namespace:

using System.ComponentModel.DataAnnotations;

Modifying the T4 Template

There are two key changes which need to be made.  The first is to insert the namespace – which I’ve done in a less than graceful manner by just dropping it into the template right after the BeginNamespace call:

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>
(itemCollection))
{
    fileManager.StartNewFile(entity.Name + ".cs");
    BeginNamespace(code);
#>
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.ComponentModel.DataAnnotations;

<#=codeStringGenerator.EntityClassOpening(entity)#> : EntityBase
{

Two things to note here – in bold – one is the base class I added previously, and the second is the DataAnnotations namespace.  Next, we’ll add the logic to prefix properties with the annotations we desire for validation.

You’re looking to move beyond the default constructor and find a section which looks like this:

foreach (var edmProperty in simpleProperties)
{

This section handles generation of (simple) properties for the entity.  There are two main conditions we want to check for – non-nullable properties (required fields) and fields with a fixed length.  Here is the full (modified) code for the section of the T4 template which generates simple properties:

Note: I started writing this by hand until found this problem  solved in the following article, but I modified the annotations to provide a bit more context (including the property names and source entity type).  What you see here is more or less copied from the linked article.

var simpleProperties = typeMapper.GetSimpleProperties(entity);
if (simpleProperties.Any())
{
foreach (var edmProperty in simpleProperties)
{
// begin max length attribute
if (code.Escape(edmProperty.TypeUsage) == "string")
{
int maxLength = 0;
if (edmProperty.TypeUsage.Facets["MaxLength"].Value != null && 
    Int32.TryParse(edmProperty.TypeUsage.Facets["MaxLength"].Value.ToString(), out maxLength))
{
#>    
    [StringLength(<#=code.CreateLiteral(maxLength)#>, 
    ErrorMessage="[The field '<#=edmProperty.Name#>' in entity '<#=entity.Name#>' cannot be longer than <#=code.CreateLiteral(maxLength)#> characters.]")]
<#
}
}
    // begin required attribute
  if (edmProperty.TypeUsage.Facets["Nullable"].Value.ToString() =="False")
  {
#>
    [Required(ErrorMessage="[Property '<#=edmProperty.Name#>' in entity '<#=entity.Name#>' is a required property.]")]
<#
    }
#>    <#=codeStringGenerator.Property(edmProperty)#>
<#
        }
    }
#>

Again, apologies for the wrapped and poorly indented code – limitations of this blogging format unfortunately.  I’ve included my copy of my model.tt below so you can get a properly formatted version.  Code in italics is original non-modified template code.

The Outcome

This produces the following generated entity – with data annotations:

// Simple Properties
[Required(ErrorMessage="[Property 'CatalogId' in entity 'Catalog' is a required property.]")]
public int CatalogId { get; set; }
        
[StringLength(100, ErrorMessage="[The field 'Title' in entity 'Catalog' cannot be longer than 100 characters.]")]
[Required(ErrorMessage="[Property 'Title' in entity 'Catalog' is a required property.]")]
public string Title { get; set; }
        
[StringLength(400, ErrorMessage="[The field 'Description' in entity 'Catalog' cannot be longer than 400 characters.]")]
public string Description { get; set; }
public Nullable<System.DateTime> DateTaken { get; set; }
        
[StringLength(50, ErrorMessage="[The field 'OriginalFilename' in entity 'Catalog' cannot be longer than 50 characters.]")]
public string OriginalFilename { get; set; }
public Nullable<int> Orientation { get; set; }
// End Simple Properties

Summary

We’re not done just yet.. but this is a start.  In part 2, I’ll be showing how this effort is put to use, by integrating it into my previously documented data access approach.  Next article should be up soon.

My Template

Here’s my [ T4 Template ]

Massively Helpful

Discover how to optimize your DevOps workflows with our cloud-based automated testing infrastructure, brought to you in partnership with Sauce Labs

Topics:

Published at DZone with permission of Rob Sanders, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}