T4 for View Generation
EF team blogged about it here and I think that it’s very useful.
First, I think that it’s easier to use than Edmgen.
Moreover, contrary to EdmGen, it allows you to use embedded metadata artifacts.
If you want to use the MS T4 template with VS 2010, don’t forget to change the xml namespaces.
XNamespace edmxns = "http://schemas.microsoft.com/ado/2008/10/edmx";
XNamespace csdlns = "http://schemas.microsoft.com/ado/2008/09/edm";
XNamespace mslns = "http://schemas.microsoft.com/ado/2008/09/mapping/cs";
XNamespace ssdlns = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl";
So you should have the following:
<#@ template language="C#" hostspecific="true"#>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="System.Data.Entity.Design" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data.Entity.Design" #>
<#@ import namespace="System.Data.Metadata.Edm" #>
<#@ import namespace="System.Data.Mapping" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#
// Find EDMX file to process: Model1.Views.tt generates views for Model1.EDMX
string edmxFileName = Path.GetFileNameWithoutExtension(this.Host.TemplateFile).ToLowerInvariant().Replace(".views", "") + ".edmx";
string edmxFilePath = Path.Combine(Path.GetDirectoryName(this.Host.TemplateFile), edmxFileName);
if (File.Exists(edmxFilePath))
{
// Call helper class to generate pre-compiled views and write to output
this.WriteLine(GenerateViews(edmxFilePath));
}
else
{
this.Error(String.Format("No views were generated. Cannot find file {0}. Ensure the project has an EDMX file and the file name of the .tt file is of the form [edmx-file-name].Views.tt", edmxFilePath));
}
// All done!
#>
<#+
private String GenerateViews(string edmxFilePath)
{
String generatedViews = String.Empty;
try
{
using (StreamWriter writer = new StreamWriter(new MemoryStream()))
{
XmlReader csdlReader = null;
XmlReader mslReader = null;
XmlReader ssdlReader = null;
// Crack open the EDMX file and get readers over the CSDL, MSL and SSDL portions
GetConceptualMappingAndStorageReaders(edmxFilePath, out csdlReader, out mslReader, out ssdlReader);
// Initialize item collections
EdmItemCollection edmItems = new EdmItemCollection(new XmlReader[] { csdlReader });
StoreItemCollection storeItems = new StoreItemCollection(new XmlReader[] { ssdlReader });
StorageMappingItemCollection mappingItems = new StorageMappingItemCollection(edmItems, storeItems, new XmlReader[] { mslReader });
// Initialize the view generator to generate views in C#
EntityViewGenerator viewGenerator = new EntityViewGenerator();
viewGenerator.LanguageOption = LanguageOption.GenerateCSharpCode;
IList<EdmSchemaError> errors = viewGenerator.GenerateViews(mappingItems, writer);
foreach (EdmSchemaError e in errors)
{
// log error
this.Error(e.Message);
}
MemoryStream memStream = writer.BaseStream as MemoryStream;
generatedViews = Encoding.UTF8.GetString(memStream.ToArray());
}
}
catch (Exception ex)
{
// log error
this.Error(ex.ToString());
}
return generatedViews;
}
private void GetConceptualMappingAndStorageReaders(string edmxFile, out XmlReader csdlReader, out XmlReader mslReader, out XmlReader ssdlReader)
{
csdlReader = null;
mslReader = null;
ssdlReader = null;
XNamespace edmxns = "http://schemas.microsoft.com/ado/2008/10/edmx";
XNamespace csdlns = "http://schemas.microsoft.com/ado/2008/09/edm";
XNamespace mslns = "http://schemas.microsoft.com/ado/2008/09/mapping/cs";
XNamespace ssdlns = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl";
XDocument edmxDoc = XDocument.Load(edmxFile);
if (edmxDoc != null)
{
XElement edmxNode = edmxDoc.Element(edmxns + "Edmx");
if (edmxNode != null)
{
XElement runtimeNode = edmxNode.Element(edmxns + "Runtime");
if (runtimeNode != null)
{
// Create XmlReader over CSDL in EDMX
XElement conceptualModelsNode = runtimeNode.Element(edmxns + "ConceptualModels");
if (conceptualModelsNode != null)
{
XElement csdlContent = conceptualModelsNode.Element(csdlns + "Schema");
if (csdlContent != null)
{
csdlReader = csdlContent.CreateReader();
}
}
// Create XmlReader over MSL in EDMX
XElement mappingsNode = runtimeNode.Element(edmxns + "Mappings");
if (mappingsNode != null)
{
XElement mslContent = mappingsNode.Element(mslns + "Mapping");
if (mslContent != null)
{
mslReader = mslContent.CreateReader();
}
}
// Create XmlReader over SSDL in EDMX
XElement storageModelsNode = runtimeNode.Element(edmxns + "StorageModels");
if (storageModelsNode != null)
{
XElement ssdlContent = storageModelsNode.Element(ssdlns + "Schema");
if (ssdlContent != null)
{
ssdlReader = ssdlContent.CreateReader();
}
}
}
}
}
}
#>