1

I have the following structure.

  • MyOrg.Api (AspNet Core Web App)
  • MoOrg.DataAccess (Containing the DbContext)

I want the Migrations live in the DataAccess Assembly. Ive tried almost every combination of configuration but cant get it work probably.

MyOrg.Api (Startup.cs)

    public void ConfigureServices(IServiceCollection services)
    {
        // default stuff.. 
        services.AddDbContext<MyOrg.DataAccess.MyDatabaseContext>(options =>
        {
            options.UseSqlite("Filename=./myDbContext.db", b => b.MigrationsAssembly("MyOrg.DataAccess"));
        });
    }

MyOrg.DataAccess

    public class MyDatabaseContext : DbContext
    {
        public DbSet<Something> Somethings { get; set; }

        public MyDatabaseContext(DbContextOptions<MyDatabaseContext> options) : base(options)
        {
        }
    }

How to do it right?

Tseng
  • 61,549
  • 15
  • 193
  • 205
dknaack
  • 60,192
  • 27
  • 155
  • 202
  • Possible duplicate of http://stackoverflow.com/questions/38705694/add-migration-with-diferent-assembly – natemcmaster Aug 02 '16 at 16:50
  • Thanks but thats not the answer i was looking for. In that answer the migrations lives in the project and not in the data access assembly. – dknaack Aug 02 '16 at 16:52
  • Check again. I'm pretty sure this is basically the same scenario. – natemcmaster Aug 02 '16 at 17:19
  • Option 1. in the other answer is basically what i want. BUT the problem is that "Update-Database" creates the database file in the bin directory of the data access assembly. When i run my app it looks for the myDbContext.db in the bin directory of the api project. – dknaack Aug 02 '16 at 18:05
  • Thanks for clarifying. That would be good to add to the question. – natemcmaster Aug 02 '16 at 18:21

2 Answers2

4

In your MyOrg.DataAccess, create a new class MigrationDbContext deriving from MyDatabaseContext with and OnConfiguring method override :

public class MigrationDbContext: MyDatabaseContext
{
    public MigrationDbContext()
    {
    }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlite("Filename=./myDbContext.db");
        base.OnConfiguring(options);
    }
}

Since .Net Core 2.1 you don't need to add a reference to Microsoft.EntityFrameworkCore.Tools, dotnet ef is a global tool.
If you use .Net Core 2.0 or above, add the Microsoft.EntityFrameworkCore.Tools.DotNet as a DotNetCliToolReference to your MyOrg.DataAccess project :

  <ItemGroup>
     <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet"
                            Version="1.1.6" />
  </ItemGroup>

Then go to your MyOrg.DataAccess project directory using a command prompt and run :
dotnet ef --startup-project ../MyOrg.Api/ migrations add Initial -c MigationDbContext
to create an initial migration named Initial (I assume ../MyOrg.Api/ is the relative path to your startup project)

To update your database run:
dotnet ef --startup-project ../MyOrg.Api/ database update

For more information read the doc Entity Framework Core tools reference - .NET CLI

agua from mars
  • 16,428
  • 4
  • 61
  • 70
1

I've managed to get it working as follows (whilst also adhering to Onion Architecture):

  1. Create a class library 'App.Core'

    • Add a 'Country' domain model to this library:

      public class Country
      {
          public int Id { get; set; }
      
          public string Name { get; set; }
      }
      
    • This is just a simple class to get things working quickly

  2. Create a class library 'App.Infrastructure'

    • Add a DbContext to this library:

      public class AppDbContext : DbContext
      {
          public DbSet<Country> Countries { get; set; }
      
          protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
          {
              optionsBuilder.UseSqlServer(@"Server=localhost;Database=App;Trusted_Connection=True;",
              x => x.MigrationsAssembly("App.Migrations"));
          }
      }
      
    • 'App.Migrations' will be our separate class library just for migrations

    • 'App.Infrastructure' needs to reference 'Microsoft.EntityFrameworkCore.SqlServer' and 'Microsoft.EntityFrameworkCore.Tools'

  3. Run dotnet ef migrations add InitialCreate

    • Do this from the command line in the 'App.Infrastructure' directory

    • This will create a 'Migrations' folder in your 'App.Infrastructure' class library with a migration called 'InitialCreate'

  4. Create a class library 'App.Migrations'

    • Move the 'Migrations' folder from 'App.Infrastructure' to 'App.Migrations' - you will need to update the namespaces after the move

    • Add a project reference in 'App.Migrations' to 'App.Infrastructure'

    • Edit the .csproj file for 'App.Migrations' and add an output path:

    netcoreapp2.1 App.Infrastructure\bin\$(Configuration)\

    • The above path will be correct if 'App.Infrastructure' and 'App.Migrations' are in the same directory, if not, the output path will need to be adjusted

    • On build this results in 'App.Migrations' being output to the 'App.Infrastructure' bin directory - we need to do this as we can't reference 'App.Migrations' in 'App.Infrastructure' as this results in a circular reference, so this is a workaround

  5. Build the solution

  6. Run dotnet ef database update from the command line in the 'App.Infrastructure' directory and this should create the database and create the 'Countries' table

  7. Run dotnet ef migrations add AddCity --project App.Migrations for your next migration

    • 'AddCity' is just another migration to create a 'Cities' table - this requires adding a 'City' class and updating the DbContext

    • Run the command from the 'App.Infrastructure' directory and the migration will be added to the 'App.Migrations' class library

  8. Remember to rebuild the solution every time a migration is added

Lee Mac
  • 15,615
  • 6
  • 32
  • 80
aic
  • 145
  • 2
  • 13