2018年9月27日 星期四

[Entity Framework 6] DB First - Create Metadata class and services with T4



 C#   Entity Framework   Code-first


Introduction


This articles was inspired by WASICHRIS’ article:


Since I have a UOW (Unit of work) pattern on my Entity Framework 6 library, every POCO entity should inherits the base entity class and has its own CRUD service class as following,


PS. We need to create a Partial class which inherits UowEntity in DB-first.




However the time for creating the Partial classes and Service classes for a whole new DB-first data model (ADO.NET Entity Data Model) is expensive, so that we will use T4 to generate them automatically.




Related articles



Environment


Visual Studio 2017 community
Entity Framework 6.1.3


Implement


T4 for Models

OK, the code is complex and I won’t give too much explanation on it.
The flow is,

1.  Load .edmx and get all entity types (EntityType) from it
2.  For every EntityType, generate a .cs file with same class name (if not exists)
3.  Write namespaces and partial class structure into the .cs file







Gist for EdmxModel-simple.tt





The difference between EdmxModel-metadata.tt and EdmxModel-simple.tt:

1.   The partial class created from EdmxModel-metadata.tt inherits UowEntity and defines the MetadataType
2.   The partial class created from EdmxModel-simple.tt only inherits UowEntity

Assume that there is a POCO: MyModel in EDMX, the above T4 will generate:
1.  MyModels.cs (by EdmxModel-simple.tt)
2.  MyModelsMetadata.cs (by EdmxModel-metadata.tt)



And their contents:

MyModels.cs
namespace JB.Infra.Util.EF.Models
{
    using System;
    using System.Collections.Generic;
   
    public partial class MyModels
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Department { get; set; }
    }
}

MyModelsMetadata.cs
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using JB.Infra.Util.EF.Entity;

namespace JB.Infra.Utility.EF.DbFirst.UnitTest.Models
{

    /// <summary>
    /// MyModels class
    /// </summary>
    [Description("My Models")]
    [MetadataType(typeof(MyModelsMetadata))]
    public partial class MyModels : UowEntity
    {

    }

    /// <summary>
    /// MyModels Metadata class
    /// </summary>
    internal class MyModelsMetadata
    {

        /// <summary>
        /// Id
        /// </summary>       
        [DisplayName("Id")]
        [Description("Id")]
        [Required(ErrorMessage = "Id is required")]
        public int Id { get; set; }

       
/// skip ...


T4 for Services

Same process on generating CRUD Service class.
Notice the relative path of .edmx is updated to “../Models”



Result:





Reference




沒有留言:

張貼留言