EF6 Code First drop tables (not entire database) when model changes - c#

I'm doing Code First development with Entity Framework 6, using Database Migrations, and I'm using a new database that is populated with sample seed data. I'd like to be able to initialize my database with that seed data any time I change the model.
The catch is this: I don't have database create permissions; because of this, I can't just utilize DropCreateDatabaseIfModelChanges.
Is there a way that I can programmatically drop all of my tables, or am I stuck manually deleting them from the database each time?

Ultimately, I didn't need to delete the tables, just the data they contained.
I ended up solving this by simply truncating a list of tables at the beginning of my Seed method, based on this answer.
protected override void Seed(MyContext context)
{
var listOfTables = new List<string> { "Table1", "Table2", "Table3" };
foreach (var tableName in listOfTables)
{
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [" + tableName + "]");
}
context.SaveChanges();
// seed data below
}

If you're not using automatic migrations, but code based migrations, you can back all the way down to the first version using the follow command:
Update-Database –TargetMigration: 0
This will follow the Down path on all of your migrations until you have a clean database. Then you can execute:
Update-Database
This will bring everything back up to date. This solution assumes you've properly maintained your Down path and seeded your data with Migrations. I do this for my integration tests to ensure I start with the data in an expected state.

My suggestion is to use the local DB or another DB you have full permission on (Azure is nice, and free if you have a MSDN account). Then migrate that final DB schema over once it's set in stone and ready for production.
That being said, this might be helpful, but I've never tried it before.

If you dont have permission access to the database, it may be better to address that issue.
Anyway:
public bool TruncateTable(string connectionString, string schema, string tableName) {
var statement = "TRUNCATE TABLE [{0}].[{1}] ;";
statement = string.Format(statement, schema, tableName);
return ExecuteSqlStatement(connectionString, statement);
}
public bool DeleteAllEntriesTable(string connectionString, string schema, string tableName) {
var statement = "DELETE FROM [{0}].[{1}] ;";
statement = string.Format(statement, schema, tableName);
return ExecuteSqlStatement(connectionString, statement);
}
public bool ExecuteSqlStatement(string connectionString, string statement, bool suppressErrors = false) {
int rowsAffected;
using (var sqlConnection = new SqlConnection(connectionString)) {
using (var sqlCommand = new SqlCommand(statement, sqlConnection)) {
try {
sqlConnection.Open();
rowsAffected = sqlCommand.ExecuteNonQuery(); // potential use
}
catch (Exception ex) {
if (!suppressErrors) {
// YOUR ERROR HANDLER HERE
}
return false;
}
}
}
return true;

Related

How to fix “Invalid operation on a closed object” exception when trying to Read an OracleDataReader

I'm creating a web API using .Net Core and the Oracle.ManagedDataAccess.Core plugin that accesses an Oracle database to retrieve a Blob field and return it as a byte array. I created a function (getBlobfromDB) that gets the Oracle connection string from an encrypted field on a SQL database, connects and uses an OraleDataReader to retrieve and return the Blob field. But when the OraleDataReader tries to Read the record, I'm getting this exception: "Invalid operation on a closed object".
When you search for this issue, the most relevant answer is this post
However, I'm 100% percent sure that user on the conn string has access since that is the schema owner, and I also tried adding the schema owner to the Select query (SELECT FIELD FROM SCHEMA_OWNER.TABLE WHERE ID = "") getting the same error
So I tried two other things, getting a different VARCHAR field from another table on the same database, still getting the same error; and trying on a different Oracle database and I was able to successfully retrieve the data. I noticed that the Oracle versions on the servers are different, 12.2 for the working one and 11.2 for the non-working, this may be the reason? I don't know what else I can do or try, I'll appreciate any help/advice that you can give me
This is the simplified function
private OracleBlob getBlobfromDB(string sSystem, string sID)
{
string sSQL = String.Empty;
string connString = String.Empty;
OracleConnection oConn = new OracleConnection();
if (string.IsNullOrWhiteSpace(sID) || string.IsNullOrWhiteSpace(sSystem) )
{
return null;
}
sSQL = "SELECT BLOB_FIELD FROM TABLE WHERE ID = " + sID;
connString = getConnectionString(sSystem);
try
{
using (oConn = new OracleConnection(connString))
{
oConn.Open();
OracleCommand oCom = new OracleCommand(sSQL, oConn);
OracleDataReader oDr = oCom.ExecuteReader();
if (oDr.HasRows)
{
//I'm able to reach to this point before getting the exception
oDr.Read();
OracleBlob blob = oDr.GetOracleBlob(0);
// Clean up
oDr.Close();
oDr.Dispose();
oCom.Dispose();
return blob;
}
else
{
// Clean up
oDr.Close();
oDr.Dispose();
oCom.Dispose();
return null;
}
}
}
catch (Exception x)
{
return null;
}
finally
{
oConn.Close();
}
}
With the Oracle.ManagedDataAccess dependency you should not Close() the connection and do not use the using clause. It seems that the dependency itself closes the connection at will.
Remove: using(){} keyword and oConn.Close() from your code.

How can create a new table in database if the table does not exist (c#)

Here is my code, it works when the database has the table "UserInformation"
public bool Save()
{
using (SqlConnection connection = new SqlConnection(ConnectionString)
{
connection.Open();
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
using (var adapter = new UserInformationTableAdapter())
{
adapter.Connection = connection;
adapter.Transaction = transaction;
var table = new HelloDataSet.UserInformationDataTable();
HelloDataSet.UserInformationRow row = table.NewUserInformationRow();
row.UserName = userName;
row.Password = password;
row.Brithday = brithday;
table.Rows.Add(row);
adapter.Update(table);
transaction.Commit();
return true;
}
}
catch (Exception e)
{
transaction.Rollback();
return false;
}
finally
{
connection.Close();
}
}
}
However, when there is no table in the database, it will not create the "UserInformation" table in the database, it will jump to "catch" exception in line "adapter.Update(table);"
So my question is how can I create a new table in database if there is no "UserInformation" table in it. In addition, if the database already has the table "UserInformation" can I add a new column "Position" in that table?
Finally, I got the answer and want to share it out. First, I have to say that I put my question in a wrong way. What I really want is I have an application, and this application is connected with a database. However, I am allowed user to switch database. So, when the user switch to a new database I would like the application copy the entire database structure (not including the data) from the old one to the new one. Also, if I make some change (could be add a new column for one or more table, or add another new table) for the database in my application code, I would like every other database know the updates and make the same change by running my new application code.
So, here is my solution. I write a framework called "SchemaManager." It will create an additional table in each database, this table contains the version of the database. So, every time when I run my application the "SchemaManager" will check my hard code database version number with the database version number, if my hard code database version number is greater than the database version number, the "SchemaManager" will check the change and do the update for me.
I know my solution is not the best, but this is what I did. If anyone have anyother solution, please share with me and other people.

Oracle ODP.Net With Entity Framework 6 - ORA-00955 on Select from Table View

I have created two apps, first with ODP.Net and without Entity - works great.
static void Main(string[] args)
{
OracleConnection con = new OracleConnection();
//using connection string attributes to connect to Oracle Database
con.ConnectionString = "user id=****;password=****;data source=" +
"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=server.org.net)(PORT=1521))(CONNECT_DATA=(SERVER=dedicated)(SERVICE_NAME=ora1)))";
con.Open();
Console.WriteLine("Connected to Oracle" + con.ServerVersion);
OracleCommand command = con.CreateCommand();
command.CommandText = "SELECT ITEM FROM TEST.ORDERS";
OracleDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("\t{0}",
reader[0]);
}
reader.Close();
// Close and Dispose OracleConnection object
con.Close();
con.Dispose();
Console.WriteLine("Disconnected");
Console.ReadKey();
}
TEST.ORDERS is a View.
Second program is using ODP.Net and EntityFramework and manaly created DbSet class (which was tested on Npgsql.EntityFramework and works great, perfect copy of the view from Oracle). The application returns error: ORA-00955.
I noticed that when the change name of the "Schema" to one that does not have a view 'ORDER', the program creates my table with the same name.
This is my begining of DbSet:
[Table("ORDERS", Schema = "TEST")]
It is possible that it is wrong. But I do not know how to build the entities that will have access to this view. The user has permission only to SELECT. I want do read-only operations.
Oracle implementation of Entity framework provider is very poor but there are some ways how to make this working.
Simple but annoying - using NULL or own database initializer implementation:
Database.SetInitializer<DatabaseContext>(null);
or
class DatabaseInitializer : IDatabaseInitializer<DatabaseContext>
{
public void InitializeDatabase(DatabaseContext context)
{
// your implementation
}
}
Database.SetInitializer(new DatabaseInitializer());
Set the initialized before first access to your database.
If you want to use migrations create your views and then add migration with ignoring changes, for instance using package console add-migration initial -ignorechanges. This will make EF ignoring the inconsistencies between the DB schema and model (because it checks only tables from ALL_TABLES, not views) so it will not try to create table. There is a bug in Oracle EF implementation that if the initial migration is empty it drops and recreates the __MigrationHistory table so either your initial migration must containt at least one table before you add the view migration or you need to add a table afterwards.
You can use Keyless Entity Types and use ToView fluent api in you DbContext. when you define an entity as ToView and do migrations, the EF assumes that view has already exist in your database and won't try to create it.
So first create model:
public class KeyLessModel
{
public string Item { get; set; }
}
And in DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<KeyLessModel>().ToView("ORDERS", "TEST");
}
public DbSet<KeyLessModel> KeyLessModels { get; set; }
For get data from view just call it like this:
var items = _dbContext.KeyLessModels.ToList();
I've tested in EF Core 3.1 and works fine.

Cache is not getting refreshed in sqldependancy

I want to refresh the data automatically when change to the database is made.
I used this documentation:
And made the code on page load as:
protected void Page_Load(object sender, EventArgs e)
{
conString = "Data Source=MITEJ5-PC\\MITEJTECHONOLY;Initial Catalog=SSISTestDatabase;Integrated Security=SSPI;";
SqlDependency.Start(conString);
using (SqlConnection connection =
new SqlConnection(conString))
{
using (SqlCommand command =
new SqlCommand(GetSQL(), connection))
{
SqlCacheDependency dependency =
new SqlCacheDependency(command);
// Refresh the cache after the number of minutes
// listed below if a change does not occur.
// This value could be stored in a configuration file.
int numberOfMinutes = 1;
DateTime expires =
DateTime.Now.AddMinutes(numberOfMinutes);
Response.Cache.SetExpires(expires);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheDependency(dependency);
connection.Open();
gv.DataSource = command.ExecuteReader();
gv.DataBind();
}
}
}
private string GetSQL()
{
return "select Name,Age,Address from tlbStudent;";
}
But when I run this , and made changes in SQL table data, it is not reflecting it on grid automatically.
Where can I be wrong in above code???
Please help me.
First you need to understand how SqlDependency works. Read The Mysterious Notification for a short introduction. Once you learn that the real feature at work is Query Notifications, you can learn about the restrictions in place for queries using notifications, see Creating a Query for Notification. Once such restriction is:
The projected columns in the SELECT statement must be explicitly stated, and table names must be qualified with two-part names. Notice that this means that all tables referenced in the statement must be in the same database.
For future problems read Troubleshooting Query Notifications.
The problem in
private string GetSQL()
{
return "select Name,Age,Address from tlbStudent;";
}
the table name should be 2 parts ""
private string GetSQL()
{
return "select Name,Age,Address from dbo.tlbStudent;";
}
according to the documentation
The projected columns in the SELECT statement must be explicitly stated, and table names must be qualified with two-part names. Notice that this means that all tables referenced in the statement must be in the same database.

Local Database Loses Changes After Build

string connectionString =
"Data Source =|DataDirectory|\\user.sdf";
User context = new User(connectionString);
Userdetail newUser = new Userdetail();
newUser.Username = txtReg.Text;
newUser.Password = txtRegPassword1.Password;
try
{
context.Userdetail.InsertOnSubmit(newUser);
context.SubmitChanges();
}
catch (ChangeConflictException)
{
context.ChangeConflicts.ResolveAll(System.Data.Linq.RefreshMode.KeepChanges);
}
I want to add the new row of data (username, password) into the existing database but unfortunately it gets added temporarily only. As soon as the program is closed, the database is reverted to what it was.. Any help would be highly appreciated
Have you seen this:
Why isn't my SubmitChanges() working in LINQ-to-SQL?
Im assuming you're using Linq to Sql.
Linq to Entities would be: context.SaveChanges();

Categories