Auto migration in EF Core in three tier application - c#

i have three tier application in Asp.net Mvc Core and use EF core,
now i want create auto migration ,
i have DAL layer that my context available here
public class AdminContext : DbContext
{
public AdminContext(DbContextOptions<AdminContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<AdsAdsCategory>()
.HasKey(bc => new { bc.AdsId, bc.AdsCategoryId });
modelBuilder.Entity<AdsAdsCategory>()
.HasOne(bc => bc.Ads)
.WithMany(b => b.AdsAdsCategories)
.HasForeignKey(bc => bc.AdsId);
modelBuilder.Entity<AdsAdsCategory>()
.HasOne(bc => bc.Category)
.WithMany(c => c.AdsAdsCategories)
.HasForeignKey(bc => bc.AdsCategoryId);
}
public DbSet<Ads> Adses { get; set; }
public DbSet<AdsCategory> AdsCategories { get; set; }
public DbSet<AdsPosition> AdsPositions { get; set; }
public DbSet<AdsCustomer> AdsCustomers { get; set; }
}
and in my application startup
i write this code
var context = app.ApplicationServices.GetService<AdminContext>();
if (!context.Database.EnsureCreated())
context.Database.Migrate();
when i run application database was created and table generate but __migrationhistory doesn't exist and migration not generate,
when in start up i remove this line code
if (!context.Database.EnsureCreated())
database was created and __migrationhistory table generated,but my model table not generate,
how i can solve this problem ?
and run auto migration in EF Core in three tier application?

You need to do the following to enable Migration in MVC .NET Core.
1-open the Package Manager Console in Visual Studio. Type and execute this code.
add-migration ClassName
pm> add-migration FirstInitialize
2-After executing the code, the migration classes will be created for your models
public partial class FirstInitialize : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
//After executing the code, this section will be automatically generated for your models
}
}
3-Then, with the following code you enter in the class section of the program.cs main method, your models will be built into a database.
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<YouDbContext>();
context.Database.Migrate();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the atabase.");
}
}
4-Each time you change your models or add a new one, you have to repeat the steps. Choose a new name for your migration every time.
Sample:
pm> add-migration SecondInitialize
*I can't speak english well

Automatic migration like in EF6 do not exist in EF core. You either have to generate your migrations before starting and then use
context.Database.Migrate();
or you drop your whole database on each launch and use
context.Database.EnsureCreated();
to recreate the updated database.
The second one wont allow you to add any migrations later on, so you have to recreate entire database each time. To delete database you can use
context.Database.EnsureDeleted();

Related

Integrating ASP.NET Core Identity db with an already created database in a Razor Pages app

I have been following this book on how to Add Identity to an existing project (specifically section 14.4). I have done the following
Added the ASP.NET Core Identity NuGet packages
Configured Startup to use Authentication Middleware and added Identity services to the DI container
Updated the EF Core data model with the Identity entities
Code for updating the EF Core data model to support Identity
namespace Hoook.Data
{
public class HoookDbContext : IdentityDbContext<ApplicationUser>
{
public HoookDbContext(DbContextOptions<HoookDbContext> options) : base(options)
{
}
public DbSet<Venture> Ventures { get; set; }
}
}
Code for custom user type which inherits from IdentityUser
namespace Hoook.Data
{
public class ApplicationUser : IdentityUser
{
}
}
Startup.cs code for adding Identity service to DI
services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<HoookDbContext>();
Now I have then ran the following command in VSCode
dotnet ef migrations add AddIdentitySchema
Then I ran dotnet ef database update
At this point I am to assume my database is updated and contains the Identity tables, but that is incorrect. How Am I to add the Identity tables to my existing database? I have searched through these 1, 2, 3 stackoverflow questions with no luck.
Adding a screenshot of my SSMS Migration History and tables. The migration took but no Identity tables have been populated.
UPDATE
It may help to note, I have created an Identity app using the .NET Core CLI with new webapp -au Indi- vidual -uld. Inside the migrations of that app after running dotnet ef database update, the Migrations up and down methods are actually populated. However in my app when adding the migration following the above steps, my Migration file looks as so:
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hoook.Migrations
{
public partial class AddIdentitySchema : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
Thanks to the comments below and #DawoodAwan, I have figured out the missing piece. I did not override the OnModelCreating method and subsequently call the base.OnModelCreating() method inside of it. The solution is in the below code. I have also gone ahead and updated the names of the default tables in this example:
using Hoook.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Hoook.Data
{
public class HoookDbContext : IdentityDbContext<ApplicationUser>
{
public HoookDbContext(DbContextOptions<HoookDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>().ToTable("Users");
builder.Entity<IdentityRole>().ToTable("Roles");
builder.Entity<IdentityUserClaim<string>>().ToTable("Claims");
builder.Entity<IdentityUserToken<string>>().ToTable("Tokens");
builder.Entity<IdentityUserLogin<string>>().ToTable("Logins");
builder.Entity<IdentityRoleClaim<string>>().ToTable("RoleClaims");
builder.Entity<IdentityUserRole<string>>().ToTable("UserRoles");
}
public DbSet<Venture> Ventures { get; set; }
}
}

C# Entity Framework Core : how to execute stored procedure and get a list of custom data?

I am trying to call a stored procedure in C# with EF Core. Just returning custom result set which is not linked to any entity.
But I am getting an error:
Cannot create a DbSet for 'ExCoResponse' because this type is not included in the model for the context.
Here is my method:
public async Task<IEnumerable<ExCoResponse>> UpdateAndGetExcoUsers()
{
return await _context
.Query<ExCoResponse>()
.FromSql("[dbo].[UsersUpdateExcoDetail]")
.ToListAsync();
}
Since i am using Core 2.1
Following worked for me:
public DbQuery<ExcoUser> ExcoUsers { get; set; }
var result = await _context
.ExcoUsers.FromSql<ExcoUser>("EXEC [dbo].[UsersUpdateExcoDetail]")
.ToListAsync();
dot net core 3.0+
1- Install Microsoft.EntityFrameworkCore.Relational package
2 - Add Entity and configuration to DbContext Model
public class ApplicationDBContext : DbContext
{
public DbSet<ExCoResponse> ExCoResponses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ExCoResponse>().HasNoKey();
} // end OnModelCreating
} // end ApplicationDBContext
3- use this query. be careful have used Microsoft.EntityFrameworkCore;
var result = dBContext
.Set<ExCoResponse>()
.FromSqlRaw("exec [dbo].[UsersUpdateExcoDetail]").ToList();

EF Core throws an exception when SaveChanges method is called

(I apologize for my English)
UPDATE
Well, now I'm feeling so dumb, I Forgot install the package of
Microsoft.Entityframeworkcore.tools
In my console app Project. I install the package and it run correctly. I don't know if this can be helpful for someone but I'll let the post open. Saludos!!!
I'm doing some tests with Entity Framework Core in a .Net Framework console application. I have my solution split into three projects: one for my models, one for my data context and one for the console app.
I'm using Mysql server for database, and create the database with migrations so easily but when I'm trying to insert some data in the database, when I call the SaveChanges method, my app throws an exception.
I need to build an enterprise app, and I need to migrate the existing database (.dbf) to a Mysql. I'm trying to use EF Core in a console application in which and doing some tests.
Disposing transaction.
Closing connection to database 'EntityFrameworkCore' on server 'localhost'.
Closed connection to database 'EntityFrameworkCore' on server 'localhost'.
An exception occurred in the database while saving changes for context type 'EntityFrameworkCore.Data.TiendaContext'.
Microsoft.EntityFrameworkCore.DbUpdateException:
An error occurred while updating the entries. See the inner exception for details.
---> System.MissingFieldException: Campo no encontrado: 'Microsoft.EntityFrameworkCore.Metadata.Internal.EntityMaterializerSource.ThrowReadValueExceptionMethod'.
This is my program class
class Program
{
static void Main(string[] args)
{
InsertCliente();
}
private static void InsertCliente()
{
using (var ctx = new TiendaContext())
{
var cliente = new Cliente { Nombre = "Pedro" };
ctx.GetService<ILoggerFactory>().AddProvider(new MyLoggerProvider());
ctx.Clientes.Add(cliente);
ctx.SaveChanges();
}
}
}
My DbContext class
public class TiendaContext:DbContext
{
public DbSet<Cliente> Clientes { get; set; }
public DbSet<Producto> Productos { get; set; }
public DbSet<Transaccion> Trasacciones { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductosTransacciones>()
.HasKey(k => new { k.ProductoId, k.TransaccionId });
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL(
"server=localhost;port=3306;database=EntityFrameworkCore;uid=root;password=408792");
}
}
From the exception you are reporting it appears the entity you are trying to save; doesnt match the database structure. Compare the entities to the tables to make sure they match.
You should update your ef core nuget package. After that, hope error will gone

Code First with MySQL does not create tables

Trying to create a code first project using Entity Framework and MySQL.
When I use context.Database.EnsureCreated(); the tables are created correctly, but I would like to use migrations so the code changes to: context.Database.Migrate(); and that is when I get the error:
MySqlException: Table 'library.publishers' doesn't exist
I do see that the database was created and there is an empty table: __efmigrationshistory but that is the only table, no publishers like it does with the EnsureCreated.
What Am I missing here?
Here is the minimal code reproducing the error:
using Microsoft.EntityFrameworkCore;
namespace mySqlEFcore
{
class Program
{
static void Main(string[] args)
{
using (var context = new LibraryContext())
{
context.Database.Migrate();
context.Publishers.Add(new Publisher { ID = 1 });
context.SaveChanges();
}
}
private class Publisher
{
public int ID { get; set; }
}
private class LibraryContext : DbContext
{
public DbSet<Publisher> Publishers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL("server=localhost;database=library;user=root;password=123456;SslMode=none;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Publisher>(entity => { entity.HasKey(e => e.ID); });
}
}
}
}
Tried running Add-Migration InitialCreate but ran into more errors ...
Added a reference Microsoft.EntityFrameworkCore.Design and now the InitialCreate shows:
System.MissingMethodException: Method not found: 'Void Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory..ctor(Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger'1, Microsoft.EntityFrameworkCore.Storage.IRelationalTypeMapper)'.
at MySql.Data.EntityFrameworkCore.Storage.Internal.MySQLCommandBuilderFactory..ctor(IDiagnosticsLogger'1 logger, IRelationalTypeMapper typeMapper)
I had the same issue. The comment from #Helder Sepulveda solved my issue.
The steps that I followed:
Open Package Manager Console.
Enable-Migrations
Add-Migration InitialCreate (or whatever name that you wish.)
Update-Database
The tables were then created in my MySQL database.

Override "dbo" schema name in EntityFramework Code First Migrations

I'm trying to create an schema independent model with EntityFramework Codefirst and an Oracle database but EF uses as defaults for migrations dbo as schema.
I overridden OnModelCreating method on my DBContext to solve this and use the user in the connectionString instead
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(string.Empty);
}
The problem is that __MigrationHistory ignores this default schema and I get this error when running first migration:
ORA-01918: User 'dbo' does not exist
Tried this msdn entry to customize the schema for this table.
CustomHistoryContext:
public class CustomHistoryContext : HistoryContext
{
public CustomHistoryContext(DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema) {}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(String.Empty);
}
}
And DBConfiguration:
public sealed class Configuration :
DbMigrationsConfiguration<Model.MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(connection, defaultSchema) => new CustomHistoryContext(connection, defaultSchema));
}
protected override void Seed(Model.Model1 context)
{
}
}
And is working fine for the first migration. But when I modify my entity model and try to reflect this change with add-migration command I get the following error:
Unable to generate an explicit migration because the following
explicit migrations are pending: [201706281804589_initial,
201706281810218_pp2]. Apply the pending explicit migrations before
attempting to generate a new explicit migration.
Looks like EF gets lost and can't find migrations history at this point.
When I comment the SetHistoryContextFactory instruction in Configuration it works for subsequent add-migration commands but this workaround isn't enough for scenarios when I want to run all migrations from scratch like deploying.
Does anyone knows if I'm in the good way to accomplish this or if there is a better workaround for this?
Go to Migrations -> Configuration.cs and below mentioned code. This fix worked for me!
class Configuration : DbMigrationsConfiguration<CodeFirstOracleProject.Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(dbc, schema) => historyContextFactory.Invoke(dbc, "YourSchemaName"));
}
}
Try runnig Enable-Migrations -force again. Then run Add-Migration SomeDescription –IgnoreChanges. After that, run "Update-Database - Verbose". This worked to me
I successfully tried the following inside the Configuration : DbMigrationsConfiguration class for Oracle, in order to change the history schema to "Test":
var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(dbc, schema) => historyContextFactory.Invoke(dbc, "Test"));
So basically, instead of trying to register a custom history context with unchanged default schema, I tried to register the default history context with changed default schema.
The result: when I run Update-Database -Script, the resulting script contains the new schema for creation of the __MigrationHistory table as well as for inserting the new history values:
create table "Test"."__MigrationHistory"
-- ...
insert into "Test"."__MigrationHistory"("MigrationId", "ContextKey", "Model", "ProductVersion") ...
However, lets be perfectly clear: I just tried what I expected to work by intuition and it did work for me. I didn't find any reliable documentation to support this solution.
open Migrations -> Configuration.cs and add
public Configuration()
{
AutomaticMigrationsEnabled = false;
var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
(dbc, schema) => historyContextFactory.Invoke(dbc, "your_schema_name_hear"));
}

Categories

Resources