I am using Entity Framework 6.1 version.
I am performing a bulk insert operation with Entity Framework. I am getting an intermittent error with DbContext:
object reference not set to an instance of object" for db context.
Here is my code:
public class ApiTimingDataProvider : IApiTimingDataProvider
{
private ApiTimingDbContext _apiDbContext;
public ApiTimingDataProvider(ApiTimingDbContext apiDbContext)
{
if (apiDbContext == null)
throw new ArgumentNullException("ApiDbContext is Null");
_apiDbContext = apiDbContext;
}
public void InsertApiData(List<ApiTimingModel> apiModelList)
{
try
{
using (var ctx = _apiDbContext)
{
using (var transactionScope = new TransactionScope())
{
// some stuff in dbcontext
ctx.Database.CommandTimeout = 600;
ctx.BulkInsert(apiModelList);
ctx.SaveChanges();
transactionScope.Complete();
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
Can anyone suggest me the reason for getting the exception?
Related
When calling for this function to create the database, an error occurs System.MissingMethodException: 'Method not found: int SQLite.SQLiteConnection.CreateTable(SQLite.CreateFlags)'
This is where it throws the error during the call for database = new TransmodLocalDB();
App.xaml.cs
public static TransmodLocalDB Database
{
get
{
if (database == null)
{
database = new TransmodLocalDB(0);
}
return database;
}
}
And here is the creation of the tables and the call could not proceed to here.
TransmodLocalDB.cs
public TransmodLocalDB()
{
try
{
database = DependencyService.Get<ISQLite>().GetConnection();
// create the tables
database.CreateTable<Account>(CreateFlags.None);
database.CreateTable<Driver>(CreateFlags.None);
database.CreateTable<Job>(CreateFlags.None);
database.CreateTable<TransportLeg>(CreateFlags.None);
database.CreateTable<Notes>(CreateFlags.None);
database.CreateTable<ImageNote>(CreateFlags.None);
database.CreateTable<Sync>(CreateFlags.None);
database.CreateTable<Enums>(CreateFlags.None);
} catch (Exception ex)
{
var me = ex.Message;
}
}
The exceptions throws before it can create the tables.
Used this library sqlite-net-pcl by Frank A. Krueger latest version 1.6.292
I have a lot of classes with this structure as you can see:
public class OrganizationUserRepository : IOrganizationUserRepository
{
private DataContext _ctx;
public OrganizationUserRepository(DataContext ctx)
{
_ctx = ctx;
}
public bool Add(OrganizationUser entity)
{
try
{
_ctx.OrganizationUsers.Add(entity);
_ctx.SaveChanges();
return true;
}
catch (Exception ex)
{
// TODO log this error
return false;
}
}
public bool Edit(OrganizationUser entity)
{
try
{
OrganizationUser Edited = _ctx.OrganizationUsers.Where(i => i.Id == entity.Id).First();
_ctx.Entry(Edited).CurrentValues.SetValues(entity);
_ctx.SaveChanges();
return true;
}
catch (Exception ex)
{
// TODO log this error
return false;
}
}
public bool Remove(string id)
{
try
{
Int64 Id = Int64.Parse(id);
OrganizationUser obj = _ctx.OrganizationUsers.Where(i => i.Id == Id).First();
_ctx.OrganizationUsers.Remove(obj);
_ctx.SaveChanges();
return true;
}
catch (Exception ex)
{
// TODO log this error
return false;
}
}
}
The db context in constructor is injected by ninject .as you can see it just one of my classes .and i have multi classes like this in another services that use a single DB .(WCF Service).But i get this error in my wcf tracelog :
ExecuteReader requires an open and available Connection. The connection's current state is open.
I am using EF code first .
I found this Wrap DbContext db = new DbContext() inusing statement. And i want to know should i use this ,if Yes how can i change my class structure to use using in my code ?
I used public Readonly DbContext .i just remove readonly and everything work fine.
I'm facing following problem:
In my project, I have done error logging into the same DB, as the application is using. That means, that if error occurs, then in each catch, there is the error stored into DB.
The problem is however, when using transactions. When error occurs, the tran rollbacks, but it also rollbacks the error logged, like in this scenario:
this is public service, used to save client changes.
public UpdateClient(client)
{
try
{
TransactionScope scope0 = new TransactionScope();
// some code
scope0.Complete();
}
catch(Exception ex)
{
Logger.LogException(ex); //log the exception into DB
}
}
this is public service, used to multiple clients changes:
public void UpdateClients(clients)
{
try
{
TransactionScope scope1 = new TransactionScope();
foreach (client c in clients)
{
UpdateClient(c);
}
scope1.Complete();
}
catch (Exception ex)
{
Logger.LogException(ex);
}
}
What happend here is, that if using UpdateClients(), and if error occurs in UpdateClient(), then it is logged into DB in UpdateClient() catch block. The scope0 is rollbacked, and doesnt affect the logged exception. But the scope1 is also rollbacked, and will rollback also the exception stored in DB in the UpdateClient() catch block.
I know, that there are options like store the errors in different DB and so on, but this is unfortunately not acceptible in current state of development.
Is there any way, how to solve this problem without major changes?
You can collect the exceptions while updating and insert them into the db outside the transaction scope:
public UpdateClient(client, bool logErrors = true)
{
try
{
TransactionScope scope0 = new TransactionScope();
// some code
scope0.Complete();
}
catch(Exception ex)
{
Logger.EnlistException(ex); // collect the exception
}
if (logErrors) Logger.WriteEnlistedExceptions();
}
public void UpdateClients(clients)
{
try
{
TransactionScope scope1 = new TransactionScope();
foreach (client c in clients)
{
UpdateClient(c, false);
}
scope1.Complete();
}
catch (Exception ex)
{
Logger.EnlistException(ex);
}
Logger.WriteEnlistedExceptions();
}
public partial class Logger
{
private static List<Exception> _exceptionList = new List<Exception>();
public static void EnlistException(Exception ex)
{
_exceptionList.Add(ex);
}
public static void WriteEnlistedExceptions()
{
foreach(Exception ex in _exceptionList)
LogException(ex);
_exceptionList.Clear();
}
}
This is of course not yet thread safe. The distinction between a call from UpdateClient or UpdateClients can be made by the stack trace of the exception.
As the answers to the question linked by Micky show, there is no way to prevent the rollback by the outer scope.
[EDIT] added logErrors flag
So I found an acceptable solution. The code will be implemented in internal method without transaction and will enlist exception in catch. Then usage is as follows:
internal UpdateClient(client)
{
try
{
// some code
}
catch(Exception ex)
{
Logger.EnlistException(ex); // collect the exception
}
}
public UpdateClient(client)
{
try
{
TransactionScope scope0 = new TransactionScope();
//call internal UpdateClient
/*internal*/ UpdateClient(client);
scope0.Complete();
}
catch(Exception ex)
{
Logger.WriteEnlistedExceptions(ex); // collect and write the exception
}
}
public void UpdateClients(clients)
{
try
{
TransactionScope scope1 = new TransactionScope();
foreach (client c in clients)
{
/*interanl*/ UpdateClient(c);
}
scope1.Complete();
}
catch (Exception ex)
{
Logger.WriteEnlistedExceptions(ex);
}
}
public partial class Logger
{
private static List<Exception> _exceptionList = new List<Exception>();
public static void EnlistException(Exception ex)
{
_exceptionList.Add(ex);
}
public static void WriteEnlistedExceptions()
{
foreach(Exception ex in _exceptionList)
LogException(ex);
_exceptionList.Clear();
}
}
This is my query where I'm returning an IEnumerable<CreditCardTransaction> to iterate through.
public partial class CreditCardTransaction
{
public static IEnumerable<CreditCardTransaction> GetUnprocessedTransactions()
{
try
{
using (var context = new SuburbanEntities())
{
return from trans in context.CreditCardTransactions
where trans.IsPublished == false
select trans;
}
}
catch (Exception ex)
{
Logging.Log("An error occurred.", "GetUnprocessedTransactions",Apps.ServicesConfig, ex);
return null;
}
}
}
This is where I am modifying those transactions once I have processed them:
public void ProcessFile()
{
try
{
_client = new TruckServiceClient();
_globalSetting = new GlobalSetting();
var unprocesstransactions = CreditCardTransaction.GetUnprocessedTransactions();
foreach (var creditCardTransaction in unprocesstransactions)
{
creditCardTransaction.IsPublished = ProcessTransaction(creditCardTransaction);
}
}
catch (Exception ex)
{
Logging.Log("An error occurred.", "ProcessCreditCardTransactions.ProcessFile", Apps.RemoteServices, ex);
}
}
I am modifying the transactions here:
creditCardTransaction.IsPublished = ProcessTransaction(creditCardTransaction);
But once I have saved them, can I update the entity directly or do I need to create another method where I pass this information back in?
The problem you don't have access to the context. Here you have some examples how to do:
https://github.com/geersch/EntityFrameworkObjectContext
If you're developing Asp.Net app, you'll have some drawbacks illustreted in this article:
http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx#managing-objectcontext-instantiation
I am trying to implement Entity Framework in my application and i should be able to commit and rollback the changes manually.
First time when i execute the update statement it updates the table successfully and i am able to rollback the changes. This is correct
But second time when i execute the update statement, it updates the table successfully and also commits the changes. So I am unable to rollback manually. This is wrong
Please let me know why it is happening and how to solve this issue.
The below code is just sample to reproduce my problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data;
namespace EFTest
{
public class DBOperations
{
NorthwindEntities NorthwindContext;
DbTransaction transObject;
public DBOperations()
{
}
public void ConnectDB()
{
try
{
if (NorthwindContext == null)
{
NorthwindContext = new NorthwindEntities();
if (NorthwindContext != null && NorthwindContext.Connection.State != ConnectionState.Open)
{
NorthwindContext.Connection.Open();
transObject = NorthwindContext.Connection.BeginTransaction(IsolationLevel.ReadUncommitted);
}
}
}
catch (Exception ex)
{
throw new Exception("Database Error " + ex.Message);
}
}
public int disconnect()
{
if (NorthwindContext != null && transObject != null)
{
try
{
transObject.Rollback();
}
catch (Exception)
{
}
transObject.Dispose();
NorthwindContext.Connection.Close();
NorthwindContext.Dispose();
}
return 0;
}
public void CommitTransaction()
{
if (NorthwindContext != null && transObject != null)
{
try
{
transObject.Commit();
}
catch (Exception)
{
}
}
}
public void RollbackTransaction()
{
if (NorthwindContext != null && transObject != null)
{
try
{
transObject.Rollback();
}
catch (Exception)
{
}
}
}
public int UpdateDB()
{
int _returnVal = 0;
try
{
NorthwindContext.ExecuteStoreCommand("UPDATE Orders SET OrderDate = GETDATE() WHERE OrderID = '10248'");
}
catch (Exception ex)
{
throw new Exception("Database Error " + ex.Message);
}
return _returnVal;
}
}
public class program
{
public program()
{
//Establishing the connection.
DBOperations _DBOperations = new DBOperations();
_DBOperations.ConnectDB();
//Update the datebase
_DBOperations.UpdateDB(); //Update the database but it doesn't commit the changes.
//Issue Rollback to rollback the transaction.
_DBOperations.RollbackTransaction(); //Successfully Rollbacks the database changes.
//Again Update the datebase
_DBOperations.UpdateDB(); //Update the database it commits the changes.
//Issue Rollback to rollback the transaction.
_DBOperations.RollbackTransaction(); //Rollback fails.
}
}
}
With TransactionScope Your DbOperations could look like this:
public class DBOperations : IDisposable
{
NorthwindEntities _context;
private TransactionScope _transactionScope;
public DBOperations()
{
this.Initialize();
}
private void Initialize()
{
try
{
this.Dispose();
this._transactionScope = new TransactionScope();
this._context = new NorthwindEntities();
// no need to open connection. Let EF manage that.
}
catch (Exception ex)
{
throw new Exception("Database Error " + ex.Message);
}
}
public void RollbackTransaction()
{
try
{
this._transactionScope.Dispose();
this._transactionScope = null;
this.Dispose();
this.Initialize();
}
catch (Exception)
{
// TODO
}
}
public int UpdateDB()
{
int _returnVal = 0;
try
{
this._context.ExecuteStoreCommand("UPDATE Orders SET OrderDate = GETDATE() WHERE OrderID = '10248'");
}
catch (Exception ex)
{
throw new Exception("Database Error " + ex.Message);
}
return _returnVal;
}
public void Dispose()
{
if (this._transactionScope != null)
{
this._transactionScope.Complete();
this._transactionScope.Dispose();
}
if (this._context != null) this._context.Dispose();
}
}
And the program:
public class program
{
public program()
{
using (DBOperations dbOperations = new DBOperations())
{
dbOperations.UpdateDB(); // Update the database no commit.
dbOperations.RollbackTransaction(); // Rollback.
dbOperations.UpdateDB(); // Update the database no commit.
dbOperations.RollbackTransaction(); // Rollback.
} // Commit on Dispose.
}
}
A connection that is opened within the scope of a TransactionScope automatically enlists in the transaction. The transaction is only committed by calling Commplete(). Disposing or unhandled exceptions will cause a rollback.
If you do more than just a store command, as in changing objects and relying on the context's change tracking, you may to implement a retry mechanism in stead of just discarding the context and the changes.
You need to assign new transaction after commit or rollback of transaction .
public program()
{
//Establishing the connection.
DBOperations _DBOperations = new DBOperations();
_DBOperations.ConnectDB();
//Update the datebase
_DBOperations.UpdateDB(); //Update the database but it doesn't commit the changes.
//Issue Rollback to rollback the transaction.
_DBOperations.RollbackTransaction(); //Successfully Rollbacks the database changes.
_DBOperations.ConnectDB(); //you need to assign new transaction because your last
//transaction is over when you commit or roll back
_DBOperations.UpdateDB(); //Update the database it commits the changes.
//Issue Rollback to rollback the transaction.
_DBOperations.RollbackTransaction(); //Rollback fails.
}