Подтвердить что ты не робот

EntityFramework 7 (EF7) Миграции. Проект DbContext и StartUp находятся в разных сборках

Я пытаюсь использовать миграции в EF7 с помощью entityframework.commands. Но мой DbContext находится в другой сборке с проектом запуска (asp.net mvc - это начальный проект, а Core.Implementation имеет DbContex).

dnx. ef migration добавить MyMigration -c MyContext

System.InvalidOperationException: не найден DbContext с именем MyContext.

Я попытался использовать пространство имен, чтобы указать на другую сборку, но это тоже не сработало. Это вообще возможно? Или мне просто нужно поставить свой контекст в сборку, где команда ef7?

4b9b3361

Ответ 1

По вопросам # 639, # 2256, # 2293, # 2294, # 2357, # 2553 и # 2748, у нас есть немного работы, которые нужно сделать в этой области.: -)

Ответ 2

ИЗМЕНИТЬ

Поскольку 1.0.0-rc1-final (возможно, раньше), этот workaroud не нужен

  • Теперь вам не нужно App.DataAccess/Startup.cs (просто удалите его, если вы использовали обходной путь ниже)
  • Вы создаете/выполняете миграцию из своего основного проекта (в данном случае App.Web)
  • Однако вам нужно указать проект (-p paramater), содержащий миграции:

cd App.Web
dnx ef migrations add NewMigration -p App.DataAccess

Если у вас несколько контекстов базы данных, вам также нужно указать, какой из них использовать (-c)

cd App.Web
dnx ef migrations add NewMigration -p App.DataAccess -c YourDbContext

КОНЕЦ РЕДАКТИРОВАНИЯ

Я нашел обходное решение для этого

Предположим, что у вас есть 2 проекта: App.Web и App.DataAccess

Вы можете добавить очень простой класс Startup к вашему App.DataAccess:

>App.Web
-->Startup.cs // your main startup
>App.DataAccess
-->path/to/ApplicationDbContext.cs
-->different/path/to/YourModels.cs
-->Startup.cs // add a simple startup class
-->project.json

Простой класс запуска (App.DataAccess\Startup.cs):

using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Data.Entity;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Configuration;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;

namespace App.DataAccess
{
    public class Startup
    {
        public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
        {
            var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
                .AddJsonFile("../App.Web/config.json"); // path to your original configuration in Web project

            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; set; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
        }
    }
}

Чем изменен ваш project.json в App.DataAccess(App.DataAccess/project.json):

{
  "version": "1.0.0-*",
  "description": "App.DataAccess Class Library",
  "authors": [ "Author" ],
  "tags": [ "" ],
  "projectUrl": "",
  "licenseUrl": "",
  "frameworks": {
    "dnx451": { }
  },

  "dependencies": {
    "EntityFramework.Commands": "7.0.0-beta7",
    "Microsoft.Framework.Configuration.Json": "1.0.0-beta7",
  },

  "commands": {
    "ef": "EntityFramework.Commands" // this line is important, it will give you access to 'dnx ef' in command line
  }
}

Все, что вам нужно сделать, это перейти к App.DataAccess и использовать dnx ef:

cd App.DataAccess
dnx ef migrations add NewMigration
dnx ef migrations remove
dnx ef database update
dnx ef ...

Ответ 3

Для ASP.NET Core 1.0 и EF Core 1.0

Предположим, что мы хотим переместить наш контекст в проект Core1RtmEmptyTest.DataLayer.

Сначала включите инструменты EF для этого субпроекта, изменив его файл project.json:

{
     // same as before

    "tools": {
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": [
                "portable-net45+win8"
            ]
        }
    },

     // same as before
}

Затем запустите команду из корня этого нового проекта (а не из корня основного проекта)

D:\path\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ migrations add InitialDatabase

Здесь также нужно указать startup-project.

И, наконец, обновить базу данных

D:\path\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ database update

Ответ 4

У меня есть обходной путь, но я использую EFCore 1.0.0, поэтому вы должны выполнить миграцию. Ниже кодовых папок вам необходимо заставить его работать:

Идея состоит в том, чтобы иметь центральный datacontext: MigrationsDataContext для обработки целых миграций базы данных. Таким образом, вы можете разместить эту миграцию в отдельном проекте, предназначенном только для миграции базы данных. Вы должны сделать MigrationsDataContext для просмотра других проектов, содержащих требуемые типы данных. Таким образом, вы можете создать экземпляр datacontext и вызвать метод OnModelCreating, вручную передающий текущий DbContext ModelBuilder в качестве параметра.

public class MigrationsDataContext : DbContext
{
    private readonly Dictionary<Type, DbContextOptions> dbCtxOpts;
    private readonly IEnumerable<Type> dbCtxTypes = new[] {
        typeof(CoreDataContext),
        typeof(DbContext1),
        typeof(DbContext2),
    };

    public MigrationsDataContext(DbContextOptions<MigrationsDataContext> options,
        IEnumerable<DbContextOptions> dbCtxOpts)
        :base(options)
    {
        this.dbCtxOpts = dbCtxOpts
            .GroupBy(o => o.ContextType)
            .ToDictionary(g => g.Key, g => g.First());
    }

    public MigrationsDataContext()
    { }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        foreach (var db in dbCtxTypes.Select(t => new { Type = t, Instance = Activator.CreateInstance(t, dbCtxOpts[t]) }))
        {
            var configurator = db.Type.GetMethod(nameof(OnModelCreating), BindingFlags.NonPublic | BindingFlags.Instance);

            configurator.Invoke(db.Instance, new[] { builder });
        }
    }
}

Чтобы получить все DbContextOptions от конструктора, вам нужно зарегистрировать весь пакет DbContextOptions<T> как DbContextOptions, это достигается путем вызова следующего метода в ConfigureServices в Startup.cs:

    public static IServiceCollection AddBundle<T>(this IServiceCollection services)
    {
        var baseType = typeof(T);

        var bundle = services
            .Where(d => baseType.GetTypeInfo().IsAssignableFrom(d.ServiceType))
            .Select(d => d.ServiceType)
            .ToList();

        foreach (var ctxType in bundle)
            services.AddScoped(baseType, s => s.GetService(ctxType));

        return services;
    }

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddEntityFrameworkSqlServer()
            .AddDbContext<CoreDataContext>(ConfigEf)
            .AddDbContext<DbContext1>(ConfigEf)
            .AddDbContext<DbContext2>(ConfigEf)
            .AddDbContext<MigrationsDataContext>(ConfigEf)
            .AddBundle<DbContextOptions>()
            .AddBundle<DbContext>();
...

Это все. Теперь вы управляете миграциями следующим образом:

перейдите к проекту Миграции, рядом с проектом MyWebApp,

`$> dotnet ef --startup-project ../MyWebApp migrations add Initial --context Migrations.MigrationsDataContext`

Надеюсь на эту помощь.