Частичные конструкторы классов и регистрация обработчиков событий

Мне нужно зарегистрировать обработчик событий для класса, который генерируется шаблоном - шаблоном T4 в EntityFramework.

В настоящее время мы отредактировали сгенерированный код, чтобы зарегистрировать обработчик в конструкторе сгенерированного класса (контекст модели).

Текущий код:

    public MyAppContext(string connectionString)
        : base(connectionString, ContainerName)
    {
        this.ContextOptions.LazyLoadingEnabled = true;
        // Register the event handler
        this.Connection.StateChange += Connection_StateChange;
    }

Проблема в том, что если код когда-либо будет заново сгенерирован в будущем, то приведенный выше код будет засорен, и обработчик событий больше не будет подключен...

Повторная генерация кода происходит автоматически из самых маленьких вещей, таких как открытие EF Designer и перемещение таблицы на холсте! Поэтому мы НЕ ДОЛЖНЫ оставлять свой код в сгенерированном классе.

Есть ли в любом случае мы можем поместить регистрацию в частичный класс и оставить сгенерированный код нетронутым???

Например, есть ли какое-то событие, которое всегда будет вызываться при вызове конструктора?

3 ответа

Решение

Ответом на эту проблему является редактирование шаблона T4 для добавления вызова метода в конце конструктора.

Этот метод в контексте частичных классов, генерируемых шаблоном, должен быть частичным методом.

Шаблон должен содержать определение для частичного метода.

Тогда ваш пользовательский частичный класс может реализовать этот метод, и он будет вызываться Конструкторами, определенными в сгенерированном частичном классе - теперь вы можете регенерировать этот частичный класс столько раз, сколько захотите, и быть уверенным, что частичный метод всегда будет вызываться - при условии никто не редактирует шаблон.

Если кто-то отредактирует шаблон и удалит определение частичного метода, вы получите ошибку компилятора - ее легко исправить.

Если кто-то редактирует шаблон и удаляет вызов частичного метода из Конструктора, то, к сожалению, компилятор не может вам помочь - что-то, о чем нужно знать!

Вот мое решение в tid-битах:

Фрагмент конструктора и частичное определение метода в коде шаблона T4 "MyApp.Context.tt" (здесь вы найдете подробное объяснение синтаксиса T4 и его использования в EntityFramework):

public <#=code.Escape(container)#>(string connectionString)
    : base(connectionString, ContainerName)
{
<#
    WriteLazyLoadingEnabled(container);
#>
    // Call the OnContextCreated() method to perform any necessary 'post creation' setup
    OnContextCreated();
}

// Define the OnContextCreated partial method so that the accompanying partial Context 
// class can implement this method.
partial void OnContextCreated();

Пользовательский частичный класс, который реализует частичный метод и подключает обработчик событий:

public partial class MyAppContext 
{
    /// <summary>
    /// Performs all 'post creation' operations for the MyAppContext 
    /// 
    /// *********************************
    /// NOTE: If you get a compiler error:
    /// 'No defining declaration found for implementing declaration of partial method 'OnContextCreated()'  
    /// then it is likely that the partial class MyApp.Context.cs does not contain a corresponding
    /// definition for the partial method OnContextCreated().
    /// This can occur if the MyApp.Context.tt template no longer generates the definition.
    /// SOLUTION: Edit the MyApp.Context.tt T4 template to ensure that that partial method is defined AND
    /// that it is called from EACH MyAppContext() constructor.
    /// *********************************
    /// 
    /// </summary>
    partial void OnContextCreated()
    {
        // Register the event handler
        this.Connection.StateChange += Connection_StateChange;
    }
}

Вы говорите об EF? Для этого есть специальный механизм расширения: частичный метод OnContextCreated().

Вы можете использовать это так:

partial class MyAppContext
{
        partial void OnContextCreated()
        {
            // Register the event handler
            this.Connection.StateChange += Connection_StateChange;
        }

        void Connection_StateChange(object sender, StateChangeEventArgs e) {

        }
}

Как насчет промежуточного базового класса?

public class Intermediate : WhateverYourBaseWas {
    public Intermediate(string connectionString, string containerName) : base(connectionString, containerName) {
        this.Connection.StateChange += Connection_StateChange;
    }
}

Тогда ваш сгенерированный класс может наследовать от этого.

Другие вопросы по тегам