суббота, 22 февраля 2014 г.

Проблемы при запуске приложения после добавления Entity Framework 6.0.x через NuGet

И снова очередная проблема с Entity Framework 6.0.x после добавления его в проект через NuGet.

После запуска приложения, при первом обращении к данным, вылетает исключение следующего содержиния:


The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.


Что говорит о том, что сборка EntityFramework.SqlServer не попадает в директорию сборки проекта. А ошибок при анализе кода Visual Studio не выдает, скорее всего, из-за того что Entity Framework использует позднее связывание с этой сборкой. Поэтому жестких ссылок на нее в коде Entity Framework не содержит. А подцепляется она в момент обращения к данным. В результате чего и генерируется исключение, что не удалось найти требуемую сборку.

Погуглив, понял, что проблема уже изъезженная. Например, тут, Rob Lang привел возможные варианты решения возникшей проблемы. Например:

    1. Указать Visual Studio явно ложить эту сборку в выходную директорию проекта, куда он билдится.
    2. Добавить в конструткор контекста данных Entity Framework строчку кода, где создавать пустую переменную со ссылкой на объект класса из этой сборки. И при сборке проекта, Visual Studio увидит эту зависимость и положить в выходную директорию нужную нам сборку.
Второй вариант более предпочтительный, т.к. отказавшить от Entity Framework мы автоматом не будем получать в выходной директории проекта уже не нужную нам сборку. Поэтому, если погуглить, то большинство решений сводится к этому варианту.

Для фикса этой баги, я добавил статичный класс, в котором добавил метод, инициирующий переменную со ссылкой на объект типа из сборки EntityFramework.SqlServer
public static class EF_FIX
    {
        public static void FixEfProviderServicesProblem()
        {
            //The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer'
            //for the 'System.Data.SqlClient' ADO.NET provider could not be loaded. 
            //Make sure the provider assembly is available to the running application. 
            //See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
 
            var instance = System.Data.Entity.SqlServer.SqlProviderServices.Instance;
        }
    }
Дальше, нам необходимо прописать вызов этого метода в конструкторе контекста данных Entity Framework:
public partial class DB : DbContext
{
    public DB() : base("name=DB")
    {
         EF_FIX.FixEfProviderServicesProblem();
    }
Но тут получаем еще одну не очень приятную вещь. После каждого обновления модели Entity Framework класс контекста данных будет обновляться и наша строчка кода будет пропадать. И нам ее надо будет в таких ситуациях не забывать каждый раз прописывать заново, что не удобно.

В своей предыдущей статье Entity Framework 6.0.x и INotifyPropertyChanged я описал как можно править код скриптов, генерирующих код модели и контекста данных. Сейчас нам как раз надо модифицировать файл *.Content.tt, в котором содержится код описывающий алогритм генерации контекста данных.

Находим в нем следующие строчки и добавляем туда нужную нам строчку кода:
EF_FIX.FixEfProviderServicesProblem();
Получаем следующее:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
  EF_FIX.FixEfProviderServicesProblem();
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
        this.Configuration.LazyLoadingEnabled = false;
<#
}
После сохранения код контекста данных обновится и в нем тоже появится наш заветный фикс бага.

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

Комментариев нет:

Отправить комментарий