How can I disable the use of the __MigrationHistory table in Entity Framework 4.3 Code First? - ef-code-first

I'm using Entity Framework 4.3 Code First with a custom database initializer like this:
public class MyContext : DbContext
{
public MyContext()
{
Database.SetInitializer(new MyContextInitializer());
}
}
public class MyContextInitializer : CreateDatabaseIfNotExists<MyContext>
{
protected override void Seed(MyContext context)
{
// Add defaults to certain tables in the database
base.Seed(context);
}
}
Whenever my model changes, I edit my POCO's and mappings manually and I update my database manually.
When I run my application again, I get this error:
Server Error in '/' Application.
The model backing the 'MyContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The model backing the 'MyContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Using EFProfiler, I also notice these queries being executed:
-- statement #1
SELECT [GroupBy1].[A1] AS [C1]
FROM (SELECT COUNT(1) AS [A1]
FROM [dbo].[__MigrationHistory] AS [Extent1]) AS [GroupBy1]
-- statement #2
SELECT TOP (1) [Project1].[C1] AS [C1],
[Project1].[MigrationId] AS [MigrationId],
[Project1].[Model] AS [Model]
FROM (SELECT [Extent1].[MigrationId] AS [MigrationId],
[Extent1].[CreatedOn] AS [CreatedOn],
[Extent1].[Model] AS [Model],
1 AS [C1]
FROM [dbo].[__MigrationHistory] AS [Extent1]) AS [Project1]
ORDER BY [Project1].[CreatedOn] DESC
How can I prevent this?

At first I was sure it was because you set the default initializer in the ctor but investigating a bit I found that the initializer isn't run when the context is created but rather when you query/add something for the first time.
The provided initializer all check model compability so you are out of luck with them. You can easily make your own initializer like this instead though:
public class Initializer : IDatabaseInitializer<Context>
{
public void InitializeDatabase(Context context)
{
if (!context.Database.Exists())
{
context.Database.Create();
Seed(context);
context.SaveChanges();
}
}
private void Seed(Context context)
{
throw new NotImplementedException();
}
}
That shouldn't check compability and if the Database is missing it will create it.
UPDATE: "Context" should be the type of your implementation of DbContext

Pass null to System.Data.Entity.Database's
public static void SetInitializer<TContext>(
IDatabaseInitializer<TContext> strategy
)
where TContext : DbContext
to disable initialization for your context. Don't implement IDatabaseInitializer to disable it.
https://msdn.microsoft.com/en-us/library/system.data.entity.database.setinitializer(v=vs.113).aspx

Related

How to enable migration in EntityFramework Core Sqlite

I have Dbset and creating database like this. When first time db is created then after I add column in dbset, then the migration does not work the table column is not found. Please help me how I can enable EF Core Sqlite migrations in Xamarin Forms.
public BaseSQLRespository(string databasePath)
{
try
{
_databasePath = databasePath;
Database.EnsureCreated();
// bool IsDatabaseCreated= ;
// Settings.IsDatabaseCreatedSettings = IsDatabaseCreated;
}
catch (Exception ex)
{
throw ex;
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
try
{
optionsBuilder.UseSqlite(string.Format("Filename={0}", _databasePath));
}
catch (Exception ex)
{
throw ex;
}
}
Assuming you created a migration for your new column using the add-migration command, you can enable the execution of migrations at runtime by calling the Migrate() method instead of EnsureCreated(). The docs for the method can be found here.
As per Microsoft's documentation, the Migrate method is incompatible with the EnsureCreated method which actually bypasses the migrations when creating the database schema - so in your case you will have to delete the old database (uninstall the app or clear it's data) before trying the new code.
Don't call EnsureCreated() before Migrate(). EnsureCreated() bypasses Migrations to create the schema, which causes Migrate() to fail.
Source: EF Core - Apply migrations at runtime
To add an initial migration, run the following command:
dotnet ef migrations add YourNameOfMigration
Next, apply the migration to the database to create the schema:
dotnet ef database update
Migrations
Every time when you add a new field to the model you should add migration and apply it to DB.
i guess your configuration is wrong, you shouldn't call Database.EnsureCreated(); in ctor because OnConfiguring() is not called yet and your database is not initialized.
you can create a method which called once your serviceProvider is started.
public static void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetRequiredService<BaseSQLRespository>();//use your service provider any thing which you can get your current created `BaseSQLRespository`
context.Database.EnsureCreated();//once call when your app is started. (it is up to you which method you used to call)
...
...
}
In Addition, here is similar topic and different solution,
you can check: Error in Database.EnsureCreated() while using Entity Framework with Sqlite in Xamarin

Asp do not generate exception for oData query

i'm developing a WebApi selfhost application with oData controllers.
I have some base controller with method get
public class ODataControllerBaseClientFilter<T> : ODataControllerBase<T> where T : class, IClientId, new()
{
public ODataControllerBaseClientFilter(IDataService<T> service) : base(service)
{
}
public override IQueryable<T> Get(string query = null)
{
var a = base.Get(query).ToArray();
return base.Get(query);
}
}
There is an error in mapping EF entity to database, so if I execute query with code
var a = base.Get(query).ToArray();
EF will generate exception and return error to the client correctly.
But if I will remove this line and just return IQuerible object, there will no any exception and no any result at client! How can i resolve this problem?
UPD: text of the error
{"Unable to determine composite primary key ordering for type
'Lk.Search.Data.Models.ReportClient'. Use the ColumnAttribute (see
http://go.microsoft.com/fwlink/?LinkId=386388) or the HasKey method
(see http://go.microsoft.com/fwlink/?LinkId=386387) to specify an
order for composite primary keys."}
UPD2: I use jquery ajax to get data from oData service (for testing I just use get request from browser)

Code First Mapping to Database Views

I have been asked to map the ASP.NET Identity classes to existing database Views for read operations, using Stored Procedures for CRUD. There are a number of StackOverflow Questions stating that is possible to map to views, also this question, this one and lastly this one.
I have mapped the classes to the Views as follows-
var applicationUser = modelBuilder.Entity<applicationUser>().HasKey(au => au.Id) //Specify our own View and Stored Procedure names instead of the default tables
.ToTable("User", "Users").MapToStoredProcedures(sp =>
{
sp.Delete(d => d.HasName("spUser_Delete", "Users"));
sp.Insert(i => i.HasName("spUser_Create", "Users"));
sp.Delete(u => u.HasName("spUser_Update", "Users"));
});
Where [Users].[User] is a SQL view retrieving data from the SQL table [Users].[tblUser].
Unfortunately I have had to leave at least one of the classes mapped to a table rather than View as Entity Framework generates the following SQL-
SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE t.TABLE_TYPE = 'BASE TABLE'
AND (t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN ('Users.ApplicationRole','Users.User','Users.AuthenticationToken','Users.UserClaim','Users.UserLogin','Users.UserRole','Users.Department','Users.PasswordResetToken','Users.UserDepartment')
OR t.TABLE_NAME = 'EdmMetadata')
go
Which returns zero as these are Views and not tables.
As a result any attempt to use the UserManager results in the exception-
Value cannot be null. Parameter name: source
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: source
Source Error:
Line 48: if (ModelState.IsValid)
Line 49: {
Line 50: var userAccount = await
UserManager.FindByNameAsync(model.UserName);
Line 51:
Line 52: if (userAccount == null)
Manually changing the query to-
SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE (t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN ('Users.ApplicationRole','Users.User','Users.AuthenticationToken','Users.UserClaim','Users.UserLogin','Users.UserRole','Users.Department','Users.PasswordResetToken','Users.UserDepartment')
OR t.TABLE_NAME = 'EdmMetadata')
go
Returns the correct nine Views and would presumably not cause the error. Simply having one of the classes mapped to a table is sufficient to convince it the database is correct and to carry on as normal.
Is there any way I can persuade Entity Framework to remove the "Is a table" requirement, or assert that the tables do exist and therefore skip this step altogether?
Edit: Following a request, the code for the UserManager is included below-
AccountController.cs
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationIdentityDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
I have managed to resolve this problem by creating a custom Database Initializer which replaces the default CreateDatabaseIfNotExists initializer. The Codeguru article on Understanding Database Initializers in Entity Framework Code First was enormously helpful in helping me understand what was going on.
Code for solution-
using System.Data.Entity;
namespace NexGen.Data.Identity
{
public class IdentityCustomInitializer : IDatabaseInitializer<ApplicationIdentityDbContext>
{
public void InitializeDatabase(ApplicationIdentityDbContext)
{
return; //Do nothing, database will already have been created using scripts
}
}
}
IdentityManager-
public class ApplicationIdentityDbContext: IdentityDbContext<ApplicationUser>
{
public ApplicationIdentityDbContext() : base("DefaultConnection")
{
Database.SetInitializer(new IdentityCustomInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
As a result of this code there are no longer any probing queries by Entity Framework attempting to check if the database exists (and failing due to the assumption that tables, rather than views, were mapped) - instead the queries are immediately against the view attempting to retrieve the user data (and then executing a Stored Procedure in the case the initial action was a registration or otherwise updating the user).
please try
[Authorize]
public class AccountController : Controller
{
public AccountController()
{
InitAccountController(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationIdentityDbContext())))
}
private InitAccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
}
some more explanations:
in EF6 code we can see the following function (DatabaseTableChecker.cs):
public bool AnyModelTableExistsInDatabase(
ObjectContext context, DbConnection connection, List<EntitySet> modelTables, string edmMetadataContextTableName)
{
var modelTablesListBuilder = new StringBuilder();
foreach (var modelTable in modelTables)
{
modelTablesListBuilder.Append("'");
modelTablesListBuilder.Append((string)modelTable.MetadataProperties["Schema"].Value);
modelTablesListBuilder.Append(".");
modelTablesListBuilder.Append(GetTableName(modelTable));
modelTablesListBuilder.Append("',");
}
modelTablesListBuilder.Remove(modelTablesListBuilder.Length - 1, 1);
using (var command = new InterceptableDbCommand(
connection.CreateCommand(), context.InterceptionContext))
{
command.CommandText = #"
SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE t.TABLE_TYPE = 'BASE TABLE'
AND (t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN (" + modelTablesListBuilder + #")
OR t.TABLE_NAME = '" + edmMetadataContextTableName + "')";
var executionStrategy = DbProviderServices.GetExecutionStrategy(connection);
try
{
return executionStrategy.Execute(
() =>
{
if (connection.State == ConnectionState.Broken)
{
connection.Close();
}
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
return (int)command.ExecuteScalar() > 0;
});
}
finally
{
if (connection.State != ConnectionState.Closed)
{
connection.Close();
}
}
}
}
which corresponds to what you discover.
From this function we may says that there is a problem if, and only if, there are/is only views mapped to the model. In this case the initializer considers the database as Existing but Empty, and he tries to create the tables.
This creates problems as there are/is still views in the database with the same name as the tables the initializer wants to create.
So a work around seems to have at least one real table mapped to the context. No need for a custom initializer in this case.
I propose it as an issue : model only mapped to views
From my understanding and tests there is no need to implement an IDatabaseInitializer having an empty InitializeDatabase method like pwdst did.
From what I saw at Understanding Database Initializers in Entity Framework Code First, it is sufficient to call
Database.SetInitializer<ApplicationIdentityDbContext>(null);
when the application is initializing, or better say, before the first time the database will be accessed.
I would not put it inside the ctor of my DbContext class to avoid setting the initializer every time a DbContext instance is created. Instead, I would put it into the application's initialization method or as one of the first statements of the Main() method.
This worked fine for my application using Entity Framework 6.

Setting exception handled in Web API ExceptionFilterAttribute

Is there any way in ASP.NET Web API to mark an exception as handled in an ExceptionFilterAttribute?
I want to handle the exception at the method level with an exception filter and stop the propagation to a globally registered exception filter.
Filter used on a controller action:
public class MethodExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
// here in MVC you could set context.ExceptionHandled = true;
}
}
}
The globally registered filter:
public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is SomeOtherException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.SomethingElse)
{
Content = new StringContent(context.Exception.Message)
};
}
}
}
Try throwing an HttpResponseException at the end of your local handling. By design, they are not caught by exception filters.
throw new HttpResponseException(context.Response);
Web API 2 is designed with inversion of control in mind. You consider the possibility for the exception to already be handled, rather than interrupting the filter execution after you handle it.
In this sense, attributes deriving from ExceptionFilterAttribute should check if the exception is already handled, which your code already does since is operator returns false for null values. In addition, after you handle the exception, you set context.Exception to null in order to avoid further handling.
To achieve this in your code, you need to replace your comment from MethodExceptionFilterAttribute with context.Exception = null to clear the exception.
It is important to note that it is not a good idea to register more than one global exception filter, due to ordering issues. For information about the execution order of attribute filters in Web API, see the following thread Order of execution with multiple filters in web api.

How to get Entity framework to create/update the Database table without saving an object

I'm in the process of adding new fields, on my class but I've noticed the table won't be created until I save an object of that class. It's a bit annoying, is there a way to force it to create that table on App start or something?
You can force the initializer at Application_Start by
protected void Application_Start()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
(new MyContext()).Database.Initialize(true);
}
I think you can use Repository and Unit of Work patterns.
Using Repository and Unit of Work patterns with Entity Framework 4.0
which the Save method is defined in IUnitOfWork interface.
public interface IUnitOfWork
{
void Save();
}

Resources