I'm trying to remove a database form my application using entity framework.
The code I use is the following:
using (var dbContext = container.Resolve<ApplicationDbContext>())
{
dbContext.Database.Delete();
}
According to msdn this should work but nothing happens.
the dbContext is registered using ContainerControlledLifetimeManager and should be the same instance used to create the DB.
Adding, updating and deleting instances of entity types needs dbContext.SaveChanges() to reflect changes.
However dbContext.Database.Delete() does not need dbContext.SaveChanges().
If you open connection for example from Sql Management Studio to your database and try to dbContext.Database.Delete() then you receive Cannot drop database "dbContext" because it is currently in use. If you restart you sql server, you drop those connections and then retry dbContext.Database.Delete() you successfully drop database.
Last thing is refresh database list in Sql Management Studio in order to see that database is not there any more.
Testing with this code snippet:
using (var dbContext = new dbContext())
{
dbContext.Database.Delete();
}
After #moguzalp and this (MSDN Database.Delete Function), I came with a solution for my case:
using System.Data.Entity;
Database.Delete("connectionStringOrName");
In my case I was trying to Recreate a mssqllocalDb database for test purposes. But whenever I used the same DbContext (or an immediately new one, disposing the first and opening another), it looked like the database was still up when I tried to create it.
Bad Example: (x)
public static void RecreateDatabase(string schemaScript)
{
using (DbContext context = new DbContext("connectionStringName"))
{
context.Database.Delete(); // Delete returns true, but...
Database database = context.Database;
database.Create(); // Database already exists!
database.ExecuteSqlCommand(schemaScript);
}
}
Working example: (/)
public static void RecreateDatabase(string schemaScript)
{
Database.Delete(); // Opens and disposes its own connection
using (DbContext context = new DbContext("connectionStringName")) // New connection
{
Database database = context.Database;
database.Create(); // Works!
database.ExecuteSqlCommand(schemaScript);
}
}
Context: I'm using this on an [AssemblyInitialize] function to test my ModelContexts
All of your changes occurred on local variable dbcontext.
That is final kick > add dbContext.SaveChanges(); at the end of your using block like so:
using (var dbContext = container.Resolve<ApplicationDbContext>())
{
dbContext.Database.Delete();
dbContext.SaveChanges();
}
Related
So, I have a Xamarin app with a local DB, and I'm using the command this.Database.Migrate() to apply any pending migration, it works fine at first, but the problem is, when I uninstall the app and install again, the app try to execute the same pending migration, and I got the error "Table 'name' already exists". Is there a way to ignore tables that already exists 'cause I don't want to delete the users local data every time they uninstall the app.
I'm using the command dotnet ef migrations add initial to create migrations.
To everyone facing this problem, I solved creating a method using SQLiteConnection. You need to add using SQLite; :
public static bool TableExists(string tableName)
{
var dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), databaseName);
using (var db = new SQLiteConnection(dbPath))
{
var info = db.GetTableInfo(tableName);
if (info.Any())
{
return true;
}
}
return false;
}
I started using EFCore.BulkExtensions for ef bulk operations, and it is working very nice.
(see https://github.com/borisdj/EFCore.BulkExtensions/)
do I need to call also to SaveChanges:
using (var db = new ReportingContext())
{
db.BulkInsertOrUpdate(entities);
db.SaveChanges();
}
or this is good enough?
using (var db = new ReportingContext())
{
db.BulkInsertOrUpdate(entities);
}
The page from the link contains the following
Under the hood uses SqlBulkCopy for Insert, for Update/Delete combines BulkInsert with raw Sql MERGE (MsSQL 2008+).
So the answer is no, you don't need to call SaveChanges because EFCore.BulkExtensions works directly with the database (SqlServer). The entities you pass may not even be attached (tracked) to the context. It uses the context just to get entity model metadata and connection/transaction info.
In a .NET Core project I have the following model:
public class WrapperContext : DbContext
{
public DbSet<WrappedFunction> Functions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseSqlite("Data Source=functions.db");
}
}
public class WrappedFunction
{
[Key]
public int FunctionId { get; set; }
public String FunctionName { get; set; }
public String AssemblyPath { get; set; }
public String FactoryName { get; set; }
}
As you can see it is an Sqlite database.
I have added the initial migration and updated the database. Before running my test application I have populated the Functions table with a single record. I can open the DB with SqliteManager to see the record is there.
I then try to access the DB with the following function:
static MUinfo getInfoFor(String command)
{
UFInfo rv = null;
using (var ctx = new WrapperContext()) // <---- record disappears here
{
foreach (var fn in ctx.Functions)
{
if (fn.FunctionName.Equals(command))
{
rv = new UFInfo()
{
AssemblyPath = fn.AssemblyPath,
FactoryName = fn.FactoryName,
CommandName = command
};
}
}
}
if (rv != null) return rv;
return "No Info for " + command;
}
However, when stepping through the debugger I see that the foreach loop never executes as there are no records in the DB. When I stop before executing the foreach I can verify (using SqliteManager) that my single record has been deleted from the database.
So, it would appear that the DbContext object is somehow deleting the data from the database. Why would that be and what have I done wrong here? I am fairly new to EntityFramework so I may have done something obvious, but it isn't obvious to me.
One additional bit of info here. The project that does the db access is a library project. I have to copy the DB over to the build directory of the application before populating it and running the application. I don't know if that makes a difference or not.
Edit 6/19/17 (18:51):
OK. A bit more information (thanks to #StevePy). Nunit3 seems to conflict with EFCore (though I don't get any errors on restore) so I couldn't create a unit test for this. So I inserted a using (var ctx...) above the one in the listing above and inserted a couple of dummy records. Then I exited that using block and when I entered the one to traverse the records they were there.
However, I then commented out the dummy insertions and reran my test. And, once again, both records disappeared. So there is something very weird going on here with EFCore.
Edit 6/20/17 (15:30):
Well, I'm still not sure what is going on but there is an odd interaction between EFCore and Microsoft.Data.Sqlite.
I decided to remove all references to EFCore and simply use SQL queries on the DB. I did this without recreating the DB (so I was using the one already created by EFCore). I noticed the exact same behavior when I created a new SqliteConnection without using EFCore.
In desperation I deleted the DB and recreated it from scratch using Microsoft.Data.Sqlite. This DB didn't have any of the EFCore information in it, obviously. I then populated the DB with some test records and went to use it. No more disappearing records.
Apparently there was something very strange in the way EFCore set up the database in the first place that caused the issue. But I don't have any idea what it was.
What is likely happening is that you are using CodeFirst /w EF, but taking a DB first approach when it comes to testing your new code. EF tracks schema changes within the database and my guess is that by you creating the table ahead of time it does not know that the schema is vetted, so it drops and recreates it on context start-up.
The fix here should be to create a "stub" test that populates a test record one time using your EF model. From there you should have a table that EF recognizes against that context and accepts. From there you can create test records in whatever editor for testing purposes.
SQLite has several limitations when it comes to schema migration that you probably will want to consider as well. (see: https://learn.microsoft.com/en-us/ef/core/providers/sqlite/limitations)
You might be better off setting up DB first, telling EF how to map to an existing SQLite schema rather than trying to use Code-First as migration is pretty limited for that DB engine.
I'm trying to create a class to perform work on the database and have the need (or preference) to use a combination of DbContext and good old fashioned ADO. Why, well EF is great for simplifying a great deal of code but ADO still has many uses for more complex methods that EF cannot yet handle.
This link on MSDN states that I can pass an existing SqlConnection to my context as follows:
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var context = new SampleContext(conn, contextOwnsConnection: false))
{
// Do Something
}
}
Now I'm using Database-First so this constructor doesn't appear as standard. I therefore created a new Partial Class file and created the appropriate constructor as follows:
public partial class MyEntities : DbContext
{
public MyEntities(System.Data.Common.DbConnection conn, bool contextOwnsConnection = false)
: base(existingConnection: conn, contextOwnsConnection: contextOwnsConnection)
{
}
}
However, when I run the code the moment it hits a call to the new DbContext constructor, I get the following UnintentionalCodeFirstException() error thrown by OnModelCreating in my EDMX file:
"Code generated using the T4 templates for Database First and Model First development may not work correctly if used in Code First mode. To continue using Database First or Model First ensure that the Entity Framework connection string is specified in the config file of executing application. To use these classes, that were generated from Database First or Model First, with Code First add any additional configuration using attributes or the DbModelBuilder API and then remove the code that throws this exception."
Am I missing something obvious here, or can it just not be done with Database-First?
Clearly, I could just use two connections, one for my SqlConnection object, and another for my DbContext object but if I can, naturally I'd prefer to use a single connection if possible.
Any and all help greatly appreciated. For full disclosure, I'm using SQL-Server 2012, .NET 4.5.1, C# and EF6.0.2.
Connection strings used by the designer are not regular connection strings. Rather they are EntityConnection strings. The difference is that entity connection strings contain additional information about where to find metadata describing the model which is in form of the edmx at design time - read more here. Code First uses just regular connection strings since it builds the model on the fly based on the code. So, the UnintentionalCodeFirstException is preventing the user from using CodeFirst functionality with edmx models because the model is specified in the edmx and not in the code and if it was allowed you would effectively end up using two different models (one from edmx and one built from the code) which very likely won't be in sync which would result in weird behavior or even could lead to data corruption and crashes/exceptions.
Since the EntityConnection is derived from DbConnection and just wraps regular connection you can use it in places where you would use the provider connection. Alternatively you can access the wrapped provider connection using the StoreConnection provider on the EntityConnection.
I know this is an old thread, but later versions of Entity Framework actually can handle a shared connection, so I offer this as an alternative answer.
You can initialize an instance of the entity container with a shared connection. Use the EntityConnection(MetadataWorkspace workspace, DbConnection connection, bool entityConnectionOwnsStoreConnection) overload and specify false for the entityConnectionOwnsStoreConnection parameter. Then pass it into your context constructor as the existing connection. The EntityConnection will then prevent the connection from being automatically closed and disposed with the context.
Example:
using (var conn = new SqlConnection("..."))
{
conn.Open();
// Execute some ADO queries.
var md = new MetadataWorkspace(new[]{"res://*/SampleModel.csdl","res://*/SampleModel.ssdl","res://*/SampleModel.msl"}, new[]{System.Reflection.Assembly.GetExecutingAssembly()});
// Create the EntityConnection so the existing connection is not disposed.
var ec = new EntityConnection(md, conn, false);
using (var context = new SampleContext(conn, contextOwnsConnection: false))
{
// Do something using the entity context.
}
// Entity context is disposed but connection remains open.
// Do more ADO stuff.
}
Yes, it was a pain to figure out this stuff by examining System.Data and Entity Framework source code.
This pattern may be used within a TransactionScope to prevent escalation to a distributed transaction by virtue of using the same database connection.
Okay, this is really weird. I made a simple database with a single table, Customer, which has a single column, Name. From the database I auto-generated an ADO.NET Entity Data Model, and I'm trying to add a new Customer to it like so:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
class Program
{
static void Main()
{
Database1Entities db = new Database1Entities();
Customer c = new Customer();
c.Name = "Harry";
db.AddToCustomer(c);
db.SaveChanges();
}
}
}
But it doesn't persist Customer "Harry" to the database! I've been scratching my head for a while now wondering why such a simple operation doesn't work. What on earth could be the problem!?
EF requires that you have a unique index for many operations.
Try adding an identity field (primary key) to your table. Delete and recreate your model and try again.
Edit:
It looks like you are running this from a console app.
Do you have a connection string in the app.config file?
Do you have more than one project in your solution?
Are you getting any exceptions?
Edit2:
Next things to try:
Use SQL Server profiler to see what is being sent to the database
Open the EF model in an editor to see the xml, check if there are any errors
Place db in a using statement to ensure the connection/transaction is closed cleanly before process exit.
OK, here's a longshot. Are you sure your connection string is pointing to the right place? And the connection is functioning?
You can verify it by using SQL Server Management Studio to add some records to your test database, and then do something like
foreach (Customer c in db.Customers)
{
Console.WriteLine(c.Name);
}
Make sure that the "Copy to Output Directory" property of the database file is not set to "Copy always." If it is, every time you rebuild the application, the database may be clobbered with a pristine copy.
See: Entity Framework not flushing data to the database