Customizing Code Generation in the ADO.NET Entity Designer

Published 24 January 08 10:10 AM | dpblogs 

 

In previous posts, I’ve described CSDL annotations, how to extract CSDL from EDMX and introduced you to how the ADO.NET Entity Designer generates code.

In this post, I’ll delve into replacing the EntityModelCodeGenerator with a SingleFileGenerator you create. Now, why would you want to do such a thing? Well, there are a number of scenarios where this is interesting and the good news is its fairly straight forward to do and there are lots of samples and documentation to help you get there.

For folks who want to jump directly into the code to see how the pieces fit, this post has links to the sources for you to tweak and reuse in your applications.

Scenario

While the EntityModelCodeGenerator does its job pretty well, it only supports what the ADO.NET Entity Designer supports. This means no code generation support from the designer for things like <Using />, code generation events and CSDL annotations, even though the public generation APIs in the EntityClassGenerator class support them.

Consider the following scenario:

You love the EDM, EF and the Entity Designer but want more control over CLR attributes on the generated classes. Danny’s post describes a nice command line experience for how to use code generation events to add CLR attributes. However, you live in Visual Studio and have gotten used to the Entity Designer experience. In addition, you also want to specify the CLR attributes to be added on a per-type & per-property basis – all within the comfort of Visual Studio.

(Btw, this mirrors a real-life scenario – 3 customers have independently asked me how to do this)

One way to address this scenario is as follows:

1.       Cook up a scheme for expressing CLR attributes as annotations in CSDL

2.       Create new SingleFileGenerator that:

a.       hooks into EF code generation events

b.      uses the metadata APIs to get at the annotations in CSDL, and

c.       turns them into CLR attributes on the generated code

3.       Next, replace EntityModelCodeGenerator with yours by setting the “Custom Tool” property for the EDMX file you want.

SampleEdmxCodeGenerator

Ok, so we’ve introduced all the players and it’s time to start the show. I’ve created a sample SingleFileGenerator (called SampleEdmxCodeGenerator) based on the sample in the VS 2008 SDK that does what I described earlier.

Here’s the pseudo-code for the GenerateCode() override in SampleEdmxCodeGenerator:

protected override byte[] GenerateCode(string inputFileContent)

{

  // Extract CSDL content from EDMX

 

  // Determine language to generate code in based on the project language

 

  // Create code generator and wire up code generation events

 

  // Generate code and log warnings/errors to the Visual Studio error window

 

  // Convert generated code into bytes to return to Visual Studio

}

 

My code generation event handlers are pretty light and look like this:

private void OnTypeGenerated(object sender,

                             TypeGeneratedEventArgs eventArgs)

{

  eventArgs.AdditionalAttributes.AddRange(

   CreateCodeAttributes(eventArgs.TypeSource)

   );

}

 

private void OnPropertyGenerated(object sender,

                                 PropertyGeneratedEventArgs eventArgs)

{

  eventArgs.AdditionalAttributes.AddRange(

   CreateCodeAttributes(eventArgs.PropertySource)

   );

}

 

The rest of the action is in the CreateCodeAttributes() method. It gets a MetadataItem as parameter and uses Linq over its metadata properties to get all CSDL annotations that start with the custom XML namespace I’ve cooked up.

Here’s what the pseudo-code looks like:

private IList<CodeAttributeDeclaration> CreateCodeAttributes(MetadataItem item)

{

  string xmlns = "http://tempuri.org/SampleAnnotations";

 

  List<CodeAttributeDeclaration> codeAttributeDeclarations =

   new List<CodeAttributeDeclaration>();

  if (item != null)

  {

    // Get our CSDL annotations from EDM metadata

    IEnumerable<MetadataProperty> metadataProperties =

      item.MetadataProperties.Where(prop => prop.Name.StartsWith(xmlns));

 

    foreach (MetadataProperty metadataProperty in metadataProperties)

    {

      string metadataPropertyValue = (string)metadataProperty.Value;

      if (!String.IsNullOrEmpty(metadataPropertyValue))

      {

        // Parse the value and create CodeAttributeDeclaration and

        // CodeAttributeArgument

      }

  }

  return codeAttributeDeclarations;

 

The parsing logic in SampleEdmxCodeGenerator is simplistic and expects multiple CLR attributes to be separated by ‘;’ and only supports string and bool attribute parameters. You could easily extend the sample to work with more complicated constructs.

Links to sources for SampleEdmxCodeGenerator including how to build, test, etc can be found here.

 Sanjay Nagamangalam
Program Manager, ADO.NET

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Diego's Data Access Blog said on January 27, 2008 3:19 AM:

Today we went live with something very dear to me: The Entity Framework Toolkits &amp; Extensions . This

# 编写人生 said on January 28, 2008 9:58 PM:

今天逛了一下ADO.NETEntityFramework团队的Blog,我对这个项目比较感兴趣,因为我也是写ORM的。:)当然了,那档次不是一个级别的。

这个项目我都不知道放了多少次鸽子了,我...

# Matthieu MEZIL said on February 19, 2008 5:43 AM:

Lorsqu'on utilise les designers LINQ To SQL ou EDM, le code .NET est généré pour nous. L'utilisation

# MichaelD!'s Tech Blog said on February 25, 2008 9:37 PM:

Holy moly releasing software is quite the process. :) After about a month or so of trying to get my Plug

# Entity Framework Design said on January 22, 2009 2:44 PM:

When VS 2010 ships it will include some significant improvements to our code generation story for the

# יוסי said on March 2, 2009 7:29 AM:

תודה רבה על הכל

המידע שימושי ביותר

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker