EF4: First SaveChanges to remote server takes ~15 min - sql-server

I have a small app, that writes some basic data to sql server (2019) on remote server.
When trying to save the first record SaveChanges is hanging for ~15 minutes, then it succeeds and continue writing the next record with no delay.
In this code I try to write single value to configuration table (columns: name, value)
internal static bool Insert(string Name, string value)
{
dbConfTable currentObj = null;
using (myDBEntities db = new myDBEntities(ConnectionString))
{
dbConfTable currentObj = db.Configurations.Create();
currentObj.Value = value;
currentObj.Name = Name;
db.Configurations.Add(currentObj);
db.SaveChanges();
}
return true;
}
Things I tried:
Pre-generate the view - did not help
SaveChanges once with no changes - Save with no changes succeeded, EFhangs
Write directly to sql using SqlCommand and then accessing using EF- SqlCommand succeeded, EF hangs
Write to local sql server - works correctly
Any idea?

Related

EF Core executing a stored procedure outside the current transaction

I am using dependency injection with Entity Framework Core and the context is created through a scope factory:
using (var scope = this._scopeFactory.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<thecontext>();
//run code here
}
A transaction is started after all the objects are created:
using (var trans = context.Database.BeginTransaction())
{
try
{
This works well but during the process I need to insert records by running a stored procedure that is outside the transaction. In other words even if the transaction is aborted I still need the results of this stored procedure insert to persist. In addition any inserts from the 'isolated' stored procedure must be available to the process running under the transaction as well as outside the current scope.
The normal method of executing the stored procedure is by getting the connection and attaching the transaction to a new command. But I need to either use a new connection that is outside the current scope so it is not bound by the transaction or perhaps there is another way?
string sql = $"theProc";
var cnn = _context.Database.GetDbConnection();
if (cnn.State == ConnectionState.Closed)
cnn.Open();
DbCommand cmd = cnn.CreateCommand();
cmd.CommandText = sql;
cmd.CommandType = CommandType.StoredProcedure;
if (_context.Database.CurrentTransaction != null)
cmd.Transaction = _context.Database.CurrentTransaction.GetDbTransaction();
I ended up doing something like:
var cnnstr = _context.Database.GetConnectionString();
var isolatedCnn = new SqlConnection(cnnstr);
isolatedCnn.Open();
using (isolatedCnn)
{
This works but is ugly for a number of reasons so I'd like to find a better solution.

Call Snowflake Procedure from Azure Function App

I have procedure in Snowflake and would like to call it from my Timer Triggered Azure Function App.
That procedure expects a parameter which is of type string. Following is my code snippet to connect to Snowflake and calling that procedure with parameter.
using (IDbConnection conn = new SnowflakeDbConnection())
{
//Connect to Snowflake
conn.ConnectionString = Environment.GetEnvironmentVariable("SnowflakeConnection");
conn.Open();
using (IDbCommand cmd = conn.CreateCommand())
{
if (conn.State == ConnectionState.Open)
{
cmd.CommandText = "SP_Snowflake_Procedure";
//cmd.CommandType = CommandType.StoredProcedure;
var date = cmd.CreateParameter();
date.ParameterName = "RUNDATE";
date.DbType = DbType.String;
date.Value = "2018-01-01";
cmd.Parameters.Add(date);
using (IDataReader dr = cmd.ExecuteReader())
{
/****************
Logic to work on data
received from SP
*****************/
}
}
}
}
When control comes to cmd.ExecuteReader(), it's failing with error:
Snowflake.Data: SQL compilation error: syntax error line 1 at position 0 unexpected 'SP_Snowflake_Procedure'.
I don't understand this Snowflake, how to call a procedure. I had a thought of, it is way similar to MS SQL. But I am wrong. I couldn't even find proper related documents.
I could use same code without procedure call but simple SELECT statement and worked fine.
Suggest me any changes here.
I can't tell from the code if you're using the ODBC driver for Snowflake or the .NET driver for Snowflake. The ODBC driver supports more features than the .NET driver, but I think executing SPs should be supported in both.
You'll need to make the call using a SQL statement that executes a query (as opposed to methods that execute non-query). It will return a table with a single row with the return from the SP. It will contain a single column with the name of the SP and the scalar value of the SP (basically what would be returned to the SQL worksheet if run in the web UI).
Here's a sample SP to test in case you need a simple one:
create or replace procedure EchoString(stringValue string)
returns VARCHAR
language JavaScript
as
$$
// Note that variables passed to Snowflake stored procedures
// muat be all CAPITAL letters when used in the body of the
// procedure code.
return STRINGVALUE
$$;
--Run the stored procedure to echo the value.
call EchoString('Echo this string.');
Here's how to call the SP from a C# project using an ODBC connection:
OdbcConnection DbConnection = new OdbcConnection("DSN=Snowflake;pwd=******");
OdbcCommand DbCommandSetup = DbConnection.CreateCommand();
DbConnection.Open();
// These two lines are only required if you get a message about no running warehouse.
// It will depend on how your calling user is set up in Snowflake.
DbCommandSetup.CommandText = "use warehouse TEST;";
DbCommandSetup.ExecuteNonQuery();
OdbcCommand DbCommand = DbConnection.CreateCommand();
DbCommand.CommandText = "call TEST.PUBLIC.ECHOSTRING('Echo this string.')";
OdbcDataReader DbReader = DbCommand.ExecuteReader();
// Note: If you define a Snowflake SP, DB, or schema in mixed case without double quoting
// the name, Snowflake will uppercase it in the catalog. You can call it from here without
// converting to upper case as long as it's not double quoted (escaped \") in the string.

How to prevent timeout error when executing a SQL Server stored procedure in ASP.NET MVC?

I have a C# ASP.NET MVC program which runs a stored procedure while loading a page. If I run the stored procedure from Microsoft SQL Server Management Studio, it takes 1 minute. However, if I try to run the same stored procedure from code, it times out.
I have added Connection Timeout=0 in web.config, but sometimes it works, sometimes not.
You can set the Timeout Command to 0 when you are calling stored procedure.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand cmd= new SqlCommand(queryString, connection);
// Setting command timeout to 0 second
cmd.CommandTimeout = 0;
try
{
cmd.ExecuteNonQuery();
}
catch(Exception ex)
{
// log ex here
}
}

SQL Server CE does not give error when there is no free space on the disk

I use SQL Server CE (Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91) in a web service. The problem is the SQL Server CE driver does not return error on ExecuteNonQuery if there is no more space on hard drive where the database is located.
Test environment & steps of test:
the database for the test is located on a drive E: (flash-disk)
there is 80kb free on the disk - the database size is 64KB
I call insert into a temp table several times (see code below) and there is no problem - the data is inserted. When enough amount or rows are inserted, the SQL Server CE allocates another 64KB
now there is 16kb free on the disk, the database size is 128KB
I call insert into a temp table several times (see code below) and after number of successful inserts - no more rows are inserted anymore and there is no error
The database is 128KB and there is no more space on drive E: for next page to be allocated. But mycommand.ExecuteNonQuery() returns 1 (this must be the number of inserted rows) and there is no error. The code looks like as this:
string connString = "Data Source=E:\temp\logs\testDB.sdf;Persist Security Info=False; max database size=4090; max buffer size=4096; default lock timeout=3000; autoshrink threshold=100; Case Sensitive=true;";
using (SqlCeConnection conn = new SqlCeConnection(connString))
{
string sql = "insert into temp (status, step, dt, data) values (1,'Register','2015-12-21 16:43:59',0,0,'Test Data')";
SqlCeCommand mycommand = conn.CreateCommand();
mycommand.CommandText = sql;
int result = mycommand.ExecuteNonQuery(); //always 1
conn.Close()
}
What I tested also is Event handler method:
public static void MessageEventHandler(object sender, SqlCeInfoMessageEventArgs e) {
foreach (SqlError error in e.Errors){
Console.WriteLine("problem with sql: " + error);
throw new Exception("problem with sql: " + error);
}
}
and before opening of the connection
conn.InfoMessage += new SqlInfoMessageEventHandler( MessageEventHandler );
But MessageEventHandler is never attached.
Is there way an error to be thrown or my code to understand the operation ExecuteNonQuery is failed (I do not want to do additional check for free space on the disk, etc.) - just error or result to be 0?

ServiceStack Ormlite transactions broken?

I am using ServiceStack.Ormlite for SQL Server and just updated from 3.9.71 to 4.0.33.0 and now transactions for direct commands are failing. I can get ORMlite transactions working or direct commands, but not both.
The complication is I am doing some very complicated DB commands and since Sql.In() for a large list of GUIDs is massively slow I have a workaround which uses db.CreateCommand() and then passes the GUID list in as a custom table type.
Thus I need a single transaction to span across ORMLite commands and direct db commands. The following code used to work and now it fails.
For instance the following code used to work. I now get errors saying that the CreateCommand() should use the transaction. When I directly try then I get the indicated cast exception:
using (var db = DB.Connection.OpenDbConnection())
{
using (var transaction = db.OpenTransaction())
{
// Some ORMLite code
db.Delete<SomeType>();
using (var command = db.CreateCommand())
{
// Direct DB command
command.CommandText = "Delete from SomeTable where ...";
command.Parameters.Add(GUIDList)
command.ExecuteNonQuery();
}
}
}
Clarification:
In the code OpenTransaction() will work for the OrmLite code, but fail on the CreateCommand code. BeginTransaction() will fail for the OrmLite code.
The actual error is at command.ExecuteNonQuery(): ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
To use Transactions in OrmLite you should use the OpenTransaction() API, e.g:
using (var trans = db.OpenTransaction())
{
//...
}
I've added a couple new API's to be able to use an OrmLite transaction with a raw ADO.NET IDbCommand in this commit.
Use a managed OrmLite DB Command
Use a managed OrmLite command with OpenCommand() which will automatically prepopulate the DB command with the current transaction, e.g:
using (var trans = db.OpenTransaction())
using (var command = db.OpenCommand())
{
command.CommandText = "Delete from SomeTable where ...";
}
Manually assign underlying DB Transaction
When using the underlying ADO.NET IDbCommand you will need to also manually assign the Transaction to the command yourself, i.e:
using (var trans = db.OpenTransaction())
using (var command = db.CreateCommand())
{
command.Transaction = trans.ToDbTransaction();
command.CommandText = "Delete from SomeTable where ...";
}
The ToDbTransaction() extension method lets you access the underlying ADO.NET IDbTransaction which is required when using the underlying ADO.NET IDbCommand.
Both of these new API's are available from v4.0.34+ that's now available on MyGet.
Here is my suggestion that works.It is based on previous answers
IDbConnection conn = DB.Connection;
IDbCommand cmd = conn.CreateCommand();
using (IDbTransaction transaction = conn.OpenTransaction())
{
//ADO.NET code
cmd.Transaction = transaction.ToDbTransaction();
cmd.CommandText = "...Some sql text";
cmd.executeNonQuery();
// Some ORMLite code
conn.Delete<SomeType>();
}

Resources