Entity Framework initial migration failed with SqlException - ef-code-first

I want to create SQL Server DB/tables using EF Model's code first approach.
Here is my simple model class
public class MyApplication
{
[Key]
public string AppID { get; set; }
public string AppName { get; set; }
}
and my DBContext class is shown here
public class PolicyDBContext : DbContext
{
public PolicyDBContext(DbContextOptions options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder OptionaBuilder)
{
if (OptionaBuilder.IsConfigured)
{
OptionaBuilder.UseSqlServer(builder => builder.EnableRetryOnFailure());
}
}
DbSet<MyApplication> AppRoles { get; set; }
}
Here is my config code in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<PolicyDBContext>(item => item.UseSqlServer("Server=MyServer;Database=MyDB;user id=testuid;Password=testpwd;");
}
Then I was able to run the "add-migration initialmigration" command successfully
but when I run the "update-database" command, it always fail with the following error
Error Number:64,State:0,Class:20
A transient exception occurred during execution. The operation will be retried after 15024ms.
Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 0 - The specified network name is no longer available.)
After executing "update-database" however, I notice that the new database always get created on my SQL Server, but with no tables in it. I think that indicates that at least my connection string is good.
As you can see from code above, I did EnableRetryOnFailure, as suggested by people in responding to issues similar to mine. But it doesn't solve my problem except that it will retry a few times (6) before finally gives up.
What am I missing here?

There are two approach in the code first option. You should use protected override void OnModelCreating(ModelBuilder modelBuilder)
{ }
You should define configuration in this method.
For more details, visit this link.

Not sure why it works this way but I now know how to fix it. It appears that I need to run update-database command twice. The first time will fail but, as I mentioned in my post, the new empty DB will be created. Now, leave the empty DB there - DO NOT DELETE IT! - and run the update-database command again. This time it will succeed and the tables will be created.

Related

Xamarin.Forms and EntityFrameworkCore 3.x how to properly create a database and apply migrations?

what is the proper way to create an EF Core database on an Android/iOS device with Xamarin.Forms and EntityFrameworkCore?
I've come across the EnsureCreated vs Migrate thing and since I'm planning on changing the database structure in the future, I'd like to be able to apply those migrations to an existing database, thus I've chosen the Migrate approach.
However, when I call the Migrate method, it doesn't seem to create a database. I've managed to make it work in case I copy the pre-generated database file on the devices beforehand, but that's not what I want. Is there a way to tell EF Core to check if there's an existing database, create a new database if not, and then apply pending migrations to it?
Here's what I've done so far:
I've created a .net standard class library "Data" that will hold all my database classes (context, models, and migrations).
I've changed the TargetFramework of the "Data" project from <TargetFramework>netstandard2.0</TargetFramework> to <TargetFrameworks>netcoreapp2.0;netstandard2.0</TargetFrameworks> so I could run PMC commands on it.
I've installed these nuget packages to the "Data" project:
EntityFrameworkCore
EntityFrameworkCore.Sqlite
EntityFrameworkCore.Tools
EntityFrameworkCore.Design
I've created a database context class. I've made two constructors for it. The default one will only be used by the PMC commands for generating migrations. The other one will be used in production.
public class MyTestContext : DbContext
{
private string _databasePath;
public DbSet<Issue> Issues { get; set; }
[Obsolete("Don't use this for production. This is only for creating migrations.")]
public MyTestContext() : this("nothing.db")
{
}
public MyTestContext(string databasePath)
{
_databasePath = databasePath;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//I've also tried Filename={_databasePath} here, didn't work either
optionsBuilder.UseSqlite($"Data Source={_databasePath}");
}
}
I've created a test model class, just to have something to play with
public class Issue
{
public string Id { get; set; }
}
I created an inital migration using this command, which completed successfully:
Add-Migration Migration001 -Context MyTestContext -Output Migrations
I added a call to the Migrate method in the App.xaml.cs of my Xamarin.Forms project to test if it works.
public partial class App : Application{
//... other code
protected override async void OnStart()
{
base.OnStart();
using (var db = new MyTestContext(_dbPath))
{
try
{
db.Database.Migrate();
db.Issues.Add(new Issue
{
Id = "TestIssueId"
});
db.SaveChanges();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
//... other code
}
The _dbPath variable contains this (on Android where I'm testing it):
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "test.db");
After all this, I'm getting this exception:
Microsoft.Data.Sqlite.SqliteException: SQLite Error 1: 'no such table: Issues'.

Use session variables in to Hangfire Recurring Job

I have integrated hangfire in to Asp.net web application and trying to use session variables in to Hangfire Recurring Job as like below :
public class Startup
{
public void Configuration(IAppBuilder app)
{
HangfireSyncServices objSync = new HangfireSyncServices();
var options = new DashboardOptions
{
Authorization = new[] { new CustomAuthorizationFilter() }
};
app.UseHangfireDashboard("/hangfire", options);
app.UseHangfireServer();
//Recurring Job
RecurringJob.AddOrUpdate("ADDRESS_SYNC", () => objSync.ADDRESS_SYNC(), Cron.MinuteInterval(30));
}
}
My “HangfireSyncServices” class as below:
public partial class HangfireSyncServices : APIPageClass
{
public void ADDRESS_SYNC()
{
string userName = Convert.ToString(Session[Constants.Sessions.LoggedInUser]).ToUpper();
//Exception throwing on above statement..
//........Rest code.......
}
}
public abstract class APIPageClass : System.Web.UI.Page
{
//common property & methods...
}
but I am getting run time exception as below at the time of getting value in to “userName”:
Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the
section in the application configuration.
I have tried to resolve above error using this LINK & other solution also but not able to resolved yet. can anyone help me on this issue.
Thanks in advance,
Hiren
Hangfire jobs don't run in the same context as asp.net, it has it's own thread pool. In fact, Hangfire jobs may even execute on a different server than the one that queued the job if you have multiple servers in your hangfire pool.
Any data that you want to have access to from within the job needs to be passed in as a method parameter. For example:
public partial class HangfireSyncServices //: APIPageClass <- you can't do this..
{
public void ADDRESS_SYNC(string userName)
{
//........Rest code.......
}
}
string userName = Convert.ToString(Session[Constants.Sessions.LoggedInUser]).ToUpper();
RecurringJob.AddOrUpdate("ADDRESS_SYNC", () => objSync.ADDRESS_SYNC(userName), Cron.MinuteInterval(30));
Note that doing the above creates a recurring task that will always execute for the same user, the one that was triggered the web request that created the job.
Next problem: you're trying to create this job in the server startup, so there is no session yet. You only get a session when a web request is in progress. I can't help you with that because I don't have any idea what you're actually trying to do.

Nancyfx using Json.net, registering dependencies error

I'm trying to use nancy with JSON.net, follow the 2 ways that i found to register the dependencies but all way get me to an InvalidOperationException with a message "Something went wrong when trying to satisfy one of the dependencies during composition, make sure that you've registered all new dependencies in the container and inspect the innerexception for more details." with an inner exection of {"Unable to resolve type: Nancy.NancyEngine"}.
I'm using self hosting to run nancy and jeep everything really simple to been able just to test.
public static void Main(string[] args)
{
try
{
var host = new NancyHost(new Uri("http://localhost:8888/"));
host.Start(); // start hosting
Console.ReadKey();
host.Stop(); // stop hosting
}
catch
{
throw;
}
}
First I create a customSerializer
public class CustomJsonSerializer : JsonSerializer
{
public CustomJsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver();
Formatting = Formatting.Indented;
}
}
and then i tried 2 ways of registering
Using IRegistrations:
public class JsonRegistration : IRegistrations
{
public IEnumerable<TypeRegistration> TypeRegistrations
{
get
{
yield return new TypeRegistration(typeof(JsonSerializer), typeof(CustomJsonSerializer));
}
}
public IEnumerable<CollectionTypeRegistration> CollectionTypeRegistrations { get; protected set; }
public IEnumerable<InstanceRegistration> InstanceRegistrations { get; protected set; }
}
And also using Bootstrapper
public class NancyBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<JsonSerializer, CustomJsonSerializer>();
}
}
Which means that when self hosting I add the custom bootstrapper
var host = new NancyHost(new Uri("http://localhost:8888/"), new NancyBootstrapper());
Both way return the same error.
Problem is actually the versions, the nancy json.net package is using Newton.Json 6.0.0.0, BUT when installing the package it will install automatically newer version that will create this problem. Not sure what has change in the Newton.JSON that will actually create this.
https://github.com/NancyFx/Nancy.Serialization.JsonNet/issues/27
Just to add my hard won knowledge in this area, after a greatly frustrating few hours using Nancy 1.4.1.
If you use a custom bootstrapper, make sure you make the call to base.ConfigureApplicationContainer(container); before you start your custom registrations.
So, not:
public class MyCustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
// MY BITS HERE...
base.ConfigureApplicationContainer(container);
}
}
but,
public class MyCustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container); // Must go first!!
// MY BITS HERE...
}
}
If you don't do this you will get the following error:
Something went wrong when trying to satisfy one of the dependencies
during composition, make sure that you've registered all new
dependencies in the container and inspect the innerexception for more
details.
with a helpful inner exception of:
Unable to resolve type: Nancy.NancyEngine
The solution of changing the order of these C# statements was actually alluded to in #StevenRobbins' excellent answer here (which I could have saved myself several hours of pain if I'd only read properly the first time).
Says Steven:
By calling "base" after you've made a manual registration you are
effectively copying over your original registration by autoregister.
Either don't call base, or call it before you do your manual
registrations.

DropCreateDataBaseAlways is not working when working with multiple db schemas with Entity Framework 6 Code First

After watching the "Enhancements to Code First Migrations: Using HasDefaultSchema and ContextKey for Multiple Model Support" section of Julie Lerman's PluralSite video, "Entity Framework 6: Ninija Edition-What's New in EF 6" (https://app.pluralsight.com/library/courses/entity-framework-6-ninja-edition-whats-new/table-of-contents), it seems there is a way to run multiple schemas under a single database in Entity Framwork 6 using Code First Migrations...
However, based on the video you still need to these package manager commands for each project that houses a separate context:
1. enable-migrations
2. add-migration [MIGRATION NAME]
3. update-database
This is fine and good if you actually care about maintaining migrations going forward, which is not a concern of mine.
What I'd like to do is have each of my Context's initializers set to DropCreateDatabaseAlways, and when I start up my client app (in this case, an MVC site), code first will create the database for the first context used, create the tables in with the correct schema for that context, and then create the tables for the rest of the contexts with the correct schema.
I don't mind if the whole database is dropped and recreated every time I hit F5.
What is happening now is the last context that is accessed in the client app is the only context tables that are created in the database... any contexts being accessed before the last get their tables blown away.
I am currently using two contexts, a Billing context and a Shipping context.
Here is my code:
My client app is an MVC website, and its HomeController's Index method looks like this:
public ActionResult Index()
{
List<Shipping.Customer>
List<Billing.Customer> billingCustomers;
using (var shippingContext = new Shipping.ShippingContext())
{
shippingCustomers = shippingContext.Customers.ToList();
}
using (var billingContext = new Billing.BillingContext())
{
billingCustomers = billingContext.Customers.ToList();
}
}
Here is my DbMigrationsConfigurationClass and ShippingContext class for the Shipping Context:
internal sealed class Configuration : DbMigrationsConfiguration<ShippingContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(ShippingContext context)
{
}
}
public class ShippingContext : DbContext
{
public ShippingContext() : base("MultipleModelDb")
{
}
static ShippingContext()
{
Database.SetInitializer(new ShippingContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Shipping");
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
class ShippingContextInitializer : DropCreateDatabaseAlways<ShippingContext>
{
}
}
Likewise, here is the DbMigrationConfiguration class for the Billing Context and the BillingContext class:
internal sealed class Configuration : DbMigrationsConfiguration<BillingContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(BillingContext context)
{
}
}
public class BillingContext : DbContext
{
public BillingContext() : base("MultipleModelDb")
{
}
static BillingContext()
{
Database.SetInitializer(new BillingContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Billing");
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
class BillingContextInitializer : DropCreateDatabaseAlways<BillingContext>
{
}
}
based on the order that the contexts are being called in the controller's action method, whichever context is accessed last is the only context that is created... the other context is wiped out.
I feel like what I'm trying to do is very simple, yet code first migrations, as well as trying to "shoehorn" Entity Framework to represent multiple contexts as separate schemas in the same physical database seems a bit "hacky"...
I'm not that versed with migrations to begin with, so what I'm trying to do might not make any sense at all.
Any feedback would be helpful.
Thanks,
Mike

EF7 + ASP.NET5 beta8 - Database initializers

I'm working on multitenant application (ASP.NET 5 + EF7). Each tenant will have separate database. I will have one separate database for tenant account data. I have registered service for EF in startup class for this separate database. I have problem with migrations. I cant create EF migration, until tenantDbContext is registered as service with specific connection string. But this conection string must be dynamic for each tenant... Any idea please? What is the best option to manage DbContexts for tenants?
Future edit - protected override void OnConfiguring was the key how to do: Is this good solution please?
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TenantDbContext>();
public class TenantDbContext : IdentityDbContext<ApplicationUser>
{
public TenantDbContext() //development database with no connectionString in constructor
{
this._connectionString = "Connection String";
}
public TenantDbContext(string ConnectionString)
{
this._connectionString = ConnectionString;
}
private string _connectionString { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
...etc
As I mentioned in comments I have not tried multi-tenant/multi-db myself but try the following:
You can use DbContext CreateIfNotExists() method. https://msdn.microsoft.com/en-us/library/system.data.entity.database.createifnotexists(v=vs.113).aspx
If you have a Migrations/Configuration.cs you can set AutomaticMigrationsEnabled property to false
Setting the initializer off is probably needed as well: Database.SetInitializer<DatabaseContext>(null);
Sorry without knowing more details like workflow of creating a new tenant (automatic from DB or is a screen filled out with the connection string and name etc.) I can't make more detailed suggestions. I would suggest that your data layer be quite abstracted from the context. It seems like a bad idea for developers to have to select the correct context. Hence the use of a factory.
An option is always requiring a tenant id to be passed into all service or repository methods. I'm guessing this would be in some kind of user claim available in the controller.

Resources