in my project I am using one of the overloads for instantiating EntityConnection.
internal static EntityConnection GetEntityConnection(string name)
{
metadataWorkspace = new MetadataWorkspace(...);
var connection = new SqlConnection(GetConnection(name));
connection.AccessToken = OptionalAccessToken(connection);
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using (var ec = new EntityConnection(metadataWorkspace, connection))
{
return ec;
}
}
I am wondering, when the EntityConnection instance gets disposed automatically thanks to the usage of using does also the open connection within get disposed?
The answer to your question lies in the reflecting of the EntityConnection. Look into that and see for yourself, if underlying connection gets disposed. Many objects do something like that
public void Dispose()
{
// dispose underlying objects
_privateMemeber.Dispose();
}
For example, there was such a bug in MySql .NET provider.
But the general rule should be, "if you have not created it, you don't dispose it". In your case, using should be used outside of GetEntityConnection
using (var ec = new GetEntityConnection(...))
After you research, if EntityConnection disposes underlying object, that should be enough.
Otherwise you need to create disposing hierarchy
using (var conn = new GetConnection(...))
using (var enConn = new GetEntityConnection(...))
{
. . . . .
}
Related
The following code uses Entity Framework 6 and Managed Oracle Providers to call an Oracle stored procedure that returns multiple cursors.
The using statement is throwing the following exception:
System.ObjectDisposedException: 'Cannot access a disposed object.Object name: 'OracleConnection'.'
If I remove the using statement and instead use the code in the following post. I get no errors.
Using Entity Framework to Call an Oracle Stored Procedure with Multiple Cursors
Why is the using statement causing an exception? It has been suggested to me that there is a bug with the Oracle Managed Provider. But, my colleagues are using the same provider and their using statements are working fine.
Example Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using Oracle.ManagedDataAccess.Client;
using System.Data.Entity.Infrastructure;
namespace MyCompany
{
public class MyClass
{
private MyDbContext _dbContext = new MyDbContext();
public MyItems GetMyItems(string id)
{
var sqlQuery = "";
var oracleParameters = new List<OracleParameter>();
var oneEntityList = new List<OneEntity>();
var twoEntityList = new List<TwoEntity>();
var threeEntityList = new List<ThreeEntity>();
sqlQuery = #"
BEGIN
MY_PACKAGE.GetMyItems(:id, :p_cursor1, :p_cursor2, :p_cursor3);
END;
";
oracleParameters = new List<OracleParameter>
{
new OracleParameter("p_id", id),
new OracleParameter("p_cursor1", OracleDbType.RefCursor, ParameterDirection.Output),
new OracleParameter("p_cursor2", OracleDbType.RefCursor, ParameterDirection.Output),
new OracleParameter("p_cursor3", OracleDbType.RefCursor, ParameterDirection.Output)
};
using (var connection = _dbContext.Database.Connection)
{
connection.Open();
var command = connection.CreateCommand();
command.CommandText = sqlQuery;
command.Parameters.AddRange(oracleParameters.ToArray());
using (var reader = command.ExecuteReader())
{
oneEntityList = ((IObjectContextAdapter)dbContext).ObjectContext
.Translate<OneEntity>(reader)
.ToList();
reader.NextResult();
twoEntityList = ((IObjectContextAdapter)dbContext).ObjectContext
.Translate<TwoEntity>(reader)
.ToList();
reader.NextResult();
threeEntityList = ((IObjectContextAdapter)dbContext).ObjectContext
.Translate<ThreeEntity>(reader)
.ToList();
}
return new MyItems { OneEntity = oneEntityList, TwoEntity = twoEntityList, ThreeEntity = threeEntityList };
}
}
}
}
It is correct and proper to use using statements around disposable objects when you own the lifetime; however, in this case: you don't! The connection here belongs to the data-context, and presumably the data-context itself is IDisposable, and it will dispose the connection when the data-context is disposed.
So: while you might be allowed to borrow the connection from the data-context for the purposes of executing queries - you shouldn't be trying to dispose it here. That would end up closing/disposing a connection at unexpected times, with unpredictable results.
Conversely: if you had a var conn = new OracleConnection(...), then clearly you do own that connection (unless you hand it to something that will manage the lifetime), and you should dispose it.
Just to complicate things further... currently, your MyClass seems to own the db-context, via:
private MyDbContext _dbContext = new MyDbContext();
So ideally, your MyClass should be disposable (: IDisposable), and disposing MyClass should cascade to dispose _dbContext.
I am accessing a DB using the generic DbConnection provided by DbProviderFactories and I have observed that I don´t need to call Open before using the connection. I provide a sample code that is working (either using "System.Data.SqlClient" or "Oracle.DataAccess.Client" as the providerInvariantName parameter). I have performed all CRUD operations with similar code without explicitly calling Open on the connection, without any noticeable error.
I understand that I don´t need to close it, since the using statement takes care of closing and disposing the connection.
But, when is the connection opened in this code, then? Is it automatically opened when I call Fill on the associated DataAdapter? Is there any consequence of not explicitly calling Open on the connection object before using it?
Because if it is unnecesary and I can save myself a couple of lines of code I will sure do. ;-)
DbProviderFactory myFactoryProvider = DbProviderFactories.GetFactory("System.Data.SqlClient");// same with "Oracle.DataAccess.Client"
using (var myConnection = myFactoryProvider.CreateConnection())
using (var myCommand = myFactoryProvider.CreateCommand())
{
try
{
// Set up the connection
myConnection.ConnectionString = _someConnectionString;
myCommand.Connection = myConnection;
myCommand.CommandText = "SELECT * FROM SOME_TABLE";
// Create DataAdapter and fill DataTable
DbDataAdapter dataAdapter = myFactoryProvider.CreateDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataTable myTable = new DataTable();
dataAdapter.Fill(myTable);
// Read the table and do something with the data
foreach (DataRow fila in myTable.Rows)
{
// Do something
}
}
catch (Exception e)
{
string message = e.ToString();
throw;
}
} //using closes and disposes the connection and the command
The connection to the db should be established and opened when the statement
dataAdapter.Fill(myTable);
runs, so your code goes well as is
I want to use a database transaction with the name( a string) in EF 6.
I found aBeginTransaction() method, but it only has a IsolationLevel Parameter: BeginTransaction(IsolationLevel)
Is there a way to use a transaction with a string in EF6?
It's a bit elaborate, but you can use an existing connection + transaction in a DbContext. I adapted the example here to create a named transaction:
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (var trn = conn.BeginTransaction("TransactionName"))
{
using (var db = new MyContext(conn, false))
{
db.Database.UseTransaction(trn);
... // your code here
}
}
}
Note that your context class should implement this constructor and that the second parameter (contextOwnsConnection) must be false. Or use a constructor that defaults to false:
public MyContext(DbConnection connection)
: base(connection, false)
{ }
I'm wondering whether I should use using statement inside another?
For example:
using(SqlConnection con = new SqlConnection(...))
{
...
using(SqlCommand cmd = new SqlCommand(...))
{
}
...
}
Are both "usings" necessary or would the first using dispose of everything when it's done?
You need to use a using statement for each object you want to dispose.
I think that you will better understand this if you know that a using statement is mostly syntactic sugar, under the hood something like this is generated:
myObject m = new myObjecyt()
try
{
// Code here
}
finally
{
m.Dispose();
}
It might be desirable in your present context to dispose of every object contained within a single using block but in many other contexts, this behavior is not desirable.
You need both because they are completely independent, each one disposes its own variable. If you have multiple consecutive using statements you can also write them like this
using(SqlConnection con = new SqlConnection(...))
using(SqlCommand cmd = new SqlCommand(...))
{
...
}
I have a windows form application with .NET 4 and Entity Framework for data layer
I need one method with transaction, but making simple tests I couldn't make it work
In BLL:
public int Insert(List<Estrutura> lista)
{
using (TransactionScope scope = new TransactionScope())
{
id = this._dal.Insert(lista);
}
}
In DAL:
public int Insert(List<Estrutura> lista)
{
using (Entities ctx = new Entities (ConnectionType.Custom))
{
ctx.AddToEstrutura(lista);
ctx.SaveChanges(); //<---exception is thrown here
}
}
"The underlying provider failed on Open."
Anyone have any ideas?
PROBLEM RESOLVED - MY SOLUTION
I solved my problem doing some changes.
In one of my DAL I use a Bulk Insert and others Entity.
The problem transaction was occurring by the fact that the bulk of the transaction (transaction sql) do not understand a transaction scope
So I separated the Entity in DAL and used the sql transaction in its running some trivial. ExecuteScalar ();
I believe that is not the most elegant way to do this, but solved my problem transaction.
Here is the code of my DAL
using (SqlConnection sourceConnection = new SqlConnection(Utils.ConnectionString()))
{
sourceConnection.Open();
using (SqlTransaction transaction = sourceConnection.BeginTransaction())
{
StringBuilder query = new StringBuilder();
query.Append("INSERT INTO...");
SqlCommand command = new SqlCommand(query.ToString(), sourceConnection, transaction);
using (SqlBulkCopy bulk = new SqlBulkCopy(sourceConnection, SqlBulkCopyOptions.KeepNulls, transaction))
{
bulk.BulkCopyTimeout = int.MaxValue;
bulk.DestinationTableName = "TABLE_NAME";
bulk.WriteToServer(myDataTable);
StringBuilder updateQuery = new StringBuilder();
//another simple insert or update can be performed here
updateQuery.Append("UPDATE... ");
command.CommandText = updateQuery.ToString();
command.Parameters.Clear();
command.Parameters.AddWithValue("#SOME_PARAM", DateTime.Now);
command.ExecuteNonQuery();
transaction.Commit();
}
}
}
thanks for the help
According to the all-mighty Google, it seems that EF will open/close connections with each call to a database. Since it's doing that, it will treat the transaction as using multiple connections (using a distributed transaction). The way to get around this is to open and close the connection manually when using it.
Here's the information on the distributed transactions issue.
Here's how to manually open and close the connection.
A small code sample:
public int Insert(List<Estrutura> lista)
{
using (TransactionScope scope = new TransactionScope())
{
using (Entities ctx = new Entities (ConnectionType.Custom))
{
ctx.Connection.Open()
id = this._dal.Insert(ctx, lista);
}
}
}
public int Insert(Entities ctx, List<Estrutura> lista)
{
ctx.AddToEstrutura(lista);
ctx.SaveChanges();
}
Instead of employing TransactionScope, it is better to employ UnitOfWork pattern while working with entity framework. please refer to:
unit of work pattern
and also;
unit of work and persistance ignorance