Entity Framework transaction for multiple edmx data insert - c#

I have an application with multiple edmx. some times I need to insert or update data in different table of different edmx.
Now I'am concern if insertion of data failed after inserting data in one table.
Which can handle by sql transaction but i want do it using Entity Frame work in multiple edmx at once.
Please help me through, i'm giving a sample code alike what i'm working on
public bool SaveInformation(Other_Admission otherAdmission, Account_Bill aBill)
{
_aRepository.OtherAdmission.Insert(otherAdmission); //Assume this is Admission edmx
aBill.StudentRoll=otherAdmission.StudentRoll;
_aBillRepository.Bill.Insert(aBill); //Assume this is Account edmx
_aRepository.SaveChanges();
_aBillRepository.SaveChanges();
return true;
}

public bool SaveInformation(Other_Admission otherAdmission, Account_Bill aBill)
{
using (var transaction = _aRepository.BeginTransaction())
{
try
{
_aRepository.OtherAdmission.Insert(otherAdmission); //Assume this is Admission edmx
aBill.StudentRoll=otherAdmission.StudentRoll;
_aBillRepository.Bill.Insert(aBill); //Assume this is Account edmx
_aRepository.SaveChanges();
_aBillRepository.SaveChanges();
return true;
}
}
catch (Exception ex)
{
transaction.Rollback();
}
}

Related

EF Core transactions - am I doing it right?

What I know is EF creates transaction for DbContext.SaveChanges.
But I need a block of operations including inserts and I need identity results from them to complete my sequence.
So what I do looks like this:
using var dbTransaction = context.DataBase.BeginTransaction();
try {
context.Add(myNewEntity);
context.SaveChanges();
otherEntity.RefId = myNewEntity.Id;
context.Update(otherEntity);
// some other inserts and updates
context.SaveChanges();
dbTransaction.Commit();
}
catch {
dbTransaction.Rollback();
throw;
}
So I call SaveChanges on inserts to get identities and not to break relations.
It looks like transactions in transactions. Is it correct? Is it how it should be done? I mean - Commit doesn't require SaveChanges? I assume it just saves the changes, but I want to be sure.
Your code will be working properly, but I prefer to do it this way:
try {
context.Add(myNewEntity);
var result= context.SaveChanges();
if(result==0){
dbTransaction.Rollback();
... return error
}
otherEntity.RefId = myNewEntity.Id;
context.Update(otherEntity);
// some other inserts and updates
result=context.SaveChanges();
if(result==0){
dbTransaction.Rollback();
... return error
}
dbTransaction.Commit();
}
catch {
dbTransaction.Rollback();
throw;
}
It is very usefull if for example you update or add or delete several records.
In this case the result will return the number of effected records and instead of result==0 I usually use if result < ...effected records I expect.

EF Core - can't add entity with the same related objects

I am porting app from EF 6 to EF Core 2.2. I have an object with some related objects inside, each one with database generated ID and GUID (db - postgresql).
I'm trying to create a generic method to add a whole object graph with all related objects the same way as in EF 6 - like this:
var res = context.Set<T>().Add(entity);
Before the insert, EF make temporary IDs, which will be replaced with real database IDs.
So, because inside different object I might have exactly the same objects (for better understanding, my subject area is medicine, I have several different analyzes that are performed from the same sample), in EF Core I can't add whole object graph like this - getting errors, for example:
Key (\"ID\")=(5) already exists
But in the EF 6 version, everything used to work - all objects are inserted including inner objects with correct IDs and GUIDs, without duplicates.
In both versions, temporary IDs in the same objects are also equal, but only in EF Core version, I'm getting this error.
I have tried add attributes
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
tried changing the DbContext
modelBuilder.Entity<Sample>().Property(e => e.ID).ValueGeneratedOnAdd();
but neither works for me - I think the problem is not here.
Also I found this article in Microsoft docs, which says
If the graph does contain duplicates, then it will be necessary to process the graph before sending it to EF to consolidate multiple instances into one.
but I'm not sure - is this about my case?
Am I doing this wrong or is it impossible in EF Core 2.2?
Magic sauce: Create an interface and implement it on object you don't want to save on the object graph, then simply do not set that object as modified. The paradigm that I was failing to understand was that I never really wanted to save a 'defining' object during a save when that object was being used to define the object being saved.
I save the defining objects with a separate process. Works perfectly.
public virtual T InsertOrUpdate(T oneObject)
{
T output = null;
if (oneObject.Id == Guid.Empty)
{
output = this.Insert(oneObject);
}
else
{
try
{
_dbContext.ChangeTracker.TrackGraph(oneObject, e =>
{
if (e.Entry.IsKeySet)
{
// See if the entry has interface with 'StaticObject'
List<Type> x = e.Entry.Entity.GetType().GetInterfaces().ToList();
if (x.Contains(typeof(IStaticObject)))
{
_logger.LogWarning($"Not tracking entry {e.Entry}");
}
else
{
e.Entry.State = EntityState.Modified;
}
}
else
{
e.Entry.State = EntityState.Added;
}
});
_dbContext.Entry(oneObject).State = EntityState.Modified;
_dbContext.SaveChanges();
output = oneObject;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Problem updating object {oneObject.Id}");
}
}
return output;
}
public virtual T Insert(T oneObject)
{
try
{
_dbContext.Attach(oneObject);
_dbContext.Entry(oneObject);
_dbContext.SaveChanges();
}
catch (Exception error)
{
_logger.LogError(error.Message, error);
}
return oneObject;
}

EntityFramework Transaction - Save to multiple tables

Will the below code rollback the changes if there are any exception while saving?
using (SampleEntities context = new SampleEntities())
{
//Code Omitted
context.EmpPercAdjustments.AddRange(pp);
context.SampleJobs.AddRange(sampleJobs);
context.SaveChanges();
}
Or
Do I need to use transaction?
using (SampleEntities context = new SampleEntities())
{
//Code Omitted
using (System.Data.Entity.DbContextTransaction tranc = context.Database.BeginTransaction( ))
{
try
{
context.EmpPercAdjustments.AddRange(pp);
context.SampleJobs.AddRange(sampleJobs);
context.SaveChanges();
tranc.Commit();
}
catch (Exception ee)
{
tranc.Rollback();
}
}
}
Are there any advantages of using one over the others?
Yes it will rollback correctly.
In this case, you do not need to run an explicit transaction, because there is one already created by Entity Framework.
Creating a transaction by calling context.Database.BeginTransaction() is good, if you want f.e. to get the Id of just inserted record, something like this:
using (SampleEntities context = new SampleEntities())
{
using (System.Data.Entity.DbContextTransaction trans = context.Database.BeginTransaction( ))
{
context.SampleJobs.Add(newJob);
context.SaveChanges();
var jobId = newJob.Id;
//do other things, then commit or rollback
trans.Commit();
}
}
In this case, after calling SaveChanges(), the changes made on context objects are applied (so you can read database generated Id of added object in your scope), but they still have to be commited or rolled back, because changes are only dirty written.
Defining an explicit transaction can also be useful, if you have multiple methods that can modify context objects, but you want to have a final say, if changes they made will be all commited or not.

Inserting Data Into Db By Entity Framework Throwing Errors

I Trying to insert the data into Database By using entity framework but it throwing error following
An error occurred while updating the entries. See the inner exception for details.
Code is Here
public int InsertUserData(UserDetail userDetail, BusinessObjects objects)
{
try
{
UserCredential objCredentials = newPersonEntity.UserCredentials
.First(cd => cd.UserName == objects.UserName);
objCredentials.Status = objects.Status;
newPersonEntity.UserDetails.Add(userDetail);
int result=newPersonEntity.SaveChanges();
return result;
}
catch (Exception ex)
{
CatchError(ex);
return 3;
}
}
Can Any One Tell what mistake i did ?
As i undestand your code snipped correctly, you don't need to perform operations with objCredentials. Or if you want to change its status, you must call
newPersonEntity.UpdateObject(objCredentials);
And the only reason, why you cannot save changes is incorrect userDetail object fields values. Check that all required fields filled correclty and don't conflict with existing key values, stored in dataBase

Database locked issue while Inserting in same table the Array of more than 1000 records by multiple client

I am facing the big issue. I have created the service stack web services in C# DotNet and Database is SQLite (v4.0.30319). My System hang / Database locked issue, some time SQlite database file also corrupted while inserting/ updating the database table by number of clients (more than one connection). All are update the same table same time. Whle One is updating other try to connect than the system hang. I have tried all the ways but not able to resolve this issue.
How can I force that One One client can update the table at one time other clients can readonly mode.
My code as below
public bool CreateAnother2(LTHR record)
{
public IDbConnection Db { get; private set; }
OrmLiteConnectionFactory factory = new OrmLiteConnectionFactory("Data Source= C:/Database/db.sqlite;Integrated Security=True;User Instance=True", ServiceStack.OrmLite.Sqlite.SqliteOrmLiteDialectProvider.Instance);
try
{
using (Db = factory.OpenDbConnection())
{
using (var trans = Db.BeginTransaction()
{
// If no error insert data
var id = (int)Db.Insert(record, selectIdentity: true);
trans.Commit();
Db.Close();
return true;
}
}
}
catch (Exception ex)
{
if (Db.State == ConnectionState.Open)
{
Db.Close();
}
}
finally
{
if (Db.State == ConnectionState.Open)
{
Db.Close();
}
}
}
Sqlite is not meant to be used concurrently by multiple clients. That is your application runnning on multiple machines, or multiple applications on the same machine accessing the same shared database-file.
There are other solutions for that use case. (think mysql, postgress, Sqlserver, Oracle ea.).
If your application uses multiple connections to the database from one application but on different threads make sure that you open the database in serialized mode.
https://www.sqlite.org/threadsafe.html

Categories

Resources