With EF, with the DataBase model, entity classes are automatically generated as defined by the DataBase, and we seem unable to intervene. What if you want to generate a custom entity class?

Here’s the idea:

1. The generated entity classes we want to customize are all partial classes to expand the generated entity classes of EF.

2, the expansion part, written in the template in advance, automatic generation

3. Each entity class is extended

Implementation method:

Install two plugins for VS2012:

  • Devart T4 Editor: Provides intelligent hints for VS.
  • T4 Toolbox: Useful for generating multiple files.

2. Create folder T4 to store template files

1) Create T4 Toolbox template file entityTemplate. tt, which is used to generate multiple entity class files

\

The code is as follows:

<# +
// <copyright file="Entity.tt" company="cqxm">
// Copyright ©. All Rights Reserved.
// </copyright>

public class Entity : CSharpTemplate
{
    private string _className;
 
    public Entity(string className)
    {
        _className = className;
    }

	public override string TransformText()
	{
		base.TransformText();
# >
namespace testEF
{
	public partial class< # = _className# > :IEntity
	{
		public string _ID 
        {
            get
            {
                returnId.ToString(); }}}} <# +
        return this.GenerationEnvironment.ToString(); }}# >
Copy the code

2) Create T4 template file entityOutput. tt and call entityTemplate. tt

\

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="EntityTemplate.tt" #>
<#
    string curPath = Path.GetDirectoryName(Host.TemplateFile);
    string destPath = Path.Combine(curPath, @ ".. \Partial");// Generate each extended entity class file to the Partial folder
    if(! Directory.Exists(destPath)) { Directory.CreateDirectory(destPath); }const string inputFile = @ ".. \ShowMe.edmx";
    var textTransform = DynamicTextTransformation.Create(this);
    var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
    foreach (var entity in GetItemsToGenerate<EntityType> (itemCollection))
    {// The extension file is automatically generated for each entity class. If it is automatic, refer to the article to enter the entity class name manually
        Entity template = new Entity(entity.Name);
        string fileName = string.Format(@"{0}\{1}.cs", destPath, entity.Name);
        template.Output.Encoding = Encoding.UTF8;
        if(File.Exists(fileName))
        {
            File.Delete(fileName);
        }
        template.RenderToFile(fileName);
    }
# >

<# +
/* The following code is used to get a list of all entity classes automatically generated by EF, copied from *.edmx\*.context.tt. No way, I can't read what code */
public class EdmMetadataLoader
{
    private readonly IDynamicHost _host;
    private readonly System.Collections.IList _errors;

    public EdmMetadataLoader(IDynamicHost host, System.Collections.IList errors)
    {
        ArgumentNotNull(host, "host");
        ArgumentNotNull(errors, "errors");

        _host = host;
        _errors = errors;
    }

    public IEnumerable<GlobalItem> CreateEdmItemCollection(string sourcePath)
    {
        ArgumentNotNull(sourcePath, "sourcePath");

        if(! ValidateInputPath(sourcePath)) {return new EdmItemCollection();
        }

        var schemaElement = LoadRootElement(_host.ResolvePath(sourcePath));
        if(schemaElement ! =null)
        {
            using (var reader = schemaElement.CreateReader())
            {
                IList<EdmSchemaError> errors;
                var itemCollection = MetadataItemCollectionFactory.CreateEdmItemCollection(new[] { reader }, out errors);

                ProcessErrors(errors, sourcePath);

                returnitemCollection; }}return new EdmItemCollection();
    }

    public string GetModelNamespace(string sourcePath)
    {
        ArgumentNotNull(sourcePath, "sourcePath");

        if(! ValidateInputPath(sourcePath)) {return string.Empty;
        }

        var model = LoadRootElement(_host.ResolvePath(sourcePath));
        if (model == null)
        {
            return string.Empty;
        }

        var attribute = model.Attribute("Namespace");
        returnattribute ! =null ? attribute.Value : "";
    }

    private bool ValidateInputPath(string sourcePath)
    {
        if (sourcePath == "$" + "edmxInputFile" + "$")
        {
            _errors.Add(
                new CompilerError(_host.TemplateFile ?? sourcePath, 0.0.string.Empty,
                    GetResourceString("Template_ReplaceVsItemTemplateToken")));
            return false;
        }

        return true;
    }

    public XElement LoadRootElement(string sourcePath)
    {
        ArgumentNotNull(sourcePath, "sourcePath");

        var root = XElement.Load(sourcePath, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
        return root.Elements()
            .Where(e => e.Name.LocalName == "Runtime")
            .Elements()
            .Where(e => e.Name.LocalName == "ConceptualModels")
            .Elements()
            .Where(e => e.Name.LocalName == "Schema")
            .FirstOrDefault()
                ?? root;
    }

    private void ProcessErrors(IEnumerable<EdmSchemaError> errors, string sourceFilePath)
    {
        foreach (var error in errors)
        {
            _errors.Add(
                newCompilerError( error.SchemaLocation ?? sourceFilePath, error.Line, error.Column, error.ErrorCode.ToString(CultureInfo.InvariantCulture), error.Message) { IsWarning = error.Severity == EdmSchemaErrorSeverity.Warning }); }}public bool IsLazyLoadingEnabled(EntityContainer container)
    {
        string lazyLoadingAttributeValue;
        var lazyLoadingAttributeName = MetadataConstants.EDM_ANNOTATION_09_02 + ":LazyLoadingEnabled";
        bool isLazyLoading;
        return! MetadataTools.TryGetStringMetadataPropertySetting(container, lazyLoadingAttributeName,out lazyLoadingAttributeValue)
            || !bool.TryParse(lazyLoadingAttributeValue, outisLazyLoading) || isLazyLoading; }}public static void ArgumentNotNull<T> (T arg, string name) where T : class
{
    if (arg == null)
    {
        throw newArgumentNullException(name); }}private static readonly Lazy<System.Resources.ResourceManager> ResourceManager =
    new Lazy<System.Resources.ResourceManager>(
        () => new System.Resources.ResourceManager("System.Data.Entity.Design".typeof(MetadataItemCollectionFactory).Assembly), isThreadSafe: true);

public static string GetResourceString(string resourceName)
{
    ArgumentNotNull(resourceName, "resourceName");

    return ResourceManager.Value.GetString(resourceName, null);
}
private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName";
public IEnumerable<T> GetItemsToGenerate<T> (IEnumerable<GlobalItem> itemCollection) where T: EdmType
{
    returnitemCollection .OfType<T>() .Where(i => ! i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) .OrderBy(i => i.Name); }# >
Copy the code

The method of generating various entity class files is very simple, just save the entityOutput. tt file, the various entity class files will be generated, very cool.

The resulting file is shown in the blue circle

\

An entity extension class:

// <autogenerated>
// This file was generated by T4 code generator EntityOutput.tt.
// Any changes made to this file manually will be lost next time the file is regenerated.
// </autogenerated>

namespace testEF
{
	public partial class Show : IEntity
	{
		public string _ID 
        {
            get
            {
                returnId.ToString(); }}}}Copy the code


\

\

This template file looks so complicated, in fact, most of it is automatically generated and copied, and I don’t really understand it myself. \

\

Reference article:

Ef-code First (3) : Use T4 template to generate similar Code

\

www.cnblogs.com/guomingfeng…

The EF architecture has finally implemented a unified Update method

www.cnblogs.com/lori/archiv…

\