Thursday, September 27, 2018

[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




No comments:

Post a Comment