Retrieve Identity value in entity framework and still able to rollback - entity-framework-4

I want to retrieve the Identity column value after inserting a row in DB using entity framework. So I have to call context.savechanges(), but in case something goes wrong after updating row and retrieving identity column value, I want to to rollback completely.
Is this possible somehow in EF 4.0.?
I know how to retrieve identity column value and by rollback I mean that the inserted row should be deleted.
My identity column is an autogenerated bigint type.

What about using TransactionScope
using (var scope = new TransactionScope())
{
using (var context = new MyContext())
{
// Insert data
context.SaveChanges();
// Do something with retrieved Id
}
// If something goes wrong and following command is not called
// transaction will rollback
scope.Complete(); // Commit
}
If you do not call Complete transaction will rollback.

Related

My Entity Framework update is inserting a new row instead of updating the one I want it to asp

I am looping through the rows in a database table and updating the account balance of each row if it meets the required conditions.
Instead of the row that meets the condition to be updated alone, it gets updated and a new row with the updated values is also created at the same time with the same query.
I use this same code in the same app to change account balances of single rows and it works perfectly. But when I make calls to it from a foreach loop, the above stated problem occurs:
public bool CreditCustomerAccount(CustomerAccount account, decimal amount)
{
try
{
if (account.Type == AccountType.Current || account.Type == AccountType.Savings)
{
account.AccountBalance += amount;
}
else
{
account.AccountBalance -= amount;
}
_context.Entry(account).State = EntityState.Modified;
_context.SaveChanges();
return true;
}
catch (Exception)
{
return false;
}
}
It updates the row in question but also creates a new database table entry with the updated details
When you post an entity directly back, EF context knows nothing about it. Check out the Attach method on a DBSet. From MS DOCS:
Attaches the given entity to the context underlying the set. That is,
the entity is placed into the context in the Unchanged state, just as
if it had been read from the database... Attach is used to repopulate
a context with an entity that is known to already exist in the
database.
SaveChanges will therefore not attempt to insert an attached entity
into the database because it is assumed to already be there.
So using Attach before modifying any properties will allow the context to "know" about the object, and any changes would then indicate the object is modified.

MVC4 Linq Database Call

Working on my first MVC app. I am using the simple membership database that comes with MVC4 to manage users and roles. My understanding is that I am having to do three steps for the Find() call below to work: get the simple membership GUID of the person logged in, use the simple membership GUID to get the ID in my Couriers database, then use that ID as the missing parameter in the Find() call below to return the model / record to edit in the view? How / what do I use as the parameter to the .Find() call? Am I on the right track, or making this a lot more complicated?
ps - I am saving the membership GUID in the Couriers database in a separate column from the Courier ID primary key column when the Courier record is created. Thank you.
public ActionResult EditCourier()
{
System.Web.Security.MembershipUser user = Membership.GetUser();
var providerUserKey = user.ProviderUserKey;
Guid userId = (Guid)providerUserKey;
String userIDstring = userId.ToString();
var model =
from c in db.Couriers
where c.CourierMembershipID == userIDstring
select c.ID;
Courier courier = db.Couriers.Find();
if (courier == null)
{
return HttpNotFound();
}
return View(courier);
}
MSDN documentation says:
Uses the primary key value to attempt to find an entity tracked by the
context. If the entity is not in the context then a query will be
executed and evaluated against the data in the data source, and null
is returned if the entity is not found in the context or in the data
source.
So if you have userId as a primary key in Couriers table then you can use .Find() like this:
Courier courier = db.Couriers.Find(userId);
Otherwise you should use standard LINQ query and then call .FirstOrDefault() or SingleOrDefault() method:
Courier courier = db.Couriers.FirstOrDefault(c=>c.CourierMembershipID == userIDstring);
EDIT:
I suppose you getting this error from next query:
var model =
from c in db.Couriers
where c.CourierMembershipID == userIDstring
select c.ID;
The reason is that you getting from this query IEnumerable<Courier> model.
For making this query to get single Courier object try to call .FirstOrDefault() at the end:
var model = (from c in db.Couriers
where c.CourierMembershipID == userIDstring
select c.ID).FirstOrDefault();

Invoke SaveChanges two times in one transaction

all, I'm new here. My problem is how to invoke savechanges two times in one transaction.
Below is my code:
var order = new Order();
// modify order's properties
db.orders.add(order);
db.SaveChanges();
db.Entry(order).reload();
// do some other work about the order entity
db.Entry(order).state = EntityState.Modified;
db.SaveChanges();
But the second SaveChanges failed. The error message is "affects the unexpected number of rows (0).The entity may be modified or deleted after loading.Refresh ObjectStateManager".
My question is how to make the second SaveChanges() works. Because the property code in order entity is an autoincrease custom string field base on a custom function in database.
Thanks
Your call to .Reload() is not needed, and as #maxlego mentioned setting the .State to modified should not be needed if you haven't changed AutoDetectChangesEnabled from its default of true.
You should be able to follow this pattern and get the desired result. You can do the following with or without the TransactionScope. The benefit of using TransactionScope is that if your second call to SaveChanges() fails with an exception then the changes made by the first call will be rolled back. On the other hand, if you want the first call of SaveChanges() to succeed even when the second call fails you should remove the TransactionScope code.
using (var db = new MyContext())
using (var scope = new TransactionScope())
{
var order = new Order();
// modify order's properties
db.orders.add(order);
db.SaveChanges();
// make additional changes...
// E.g. assuming order.ID is an auto-incrementing primary key
// that is determined by the database I can now use the
// value the database set to log this change...
// save changes
db.SaveChanges();
// commit the transaction
scope.Complete();
}

how can i just update a part of then fields when table 's all fields are not nullable but have default value

mysql fields look like:
Entity Framework with mysql on existting database
my application is a mvc 4 project using EF 4.4 on mysql with a existting database.
how can i just update a part of then fields when table 's all fields are not nullable but have default value .
when create or update persistent to database for a part of field, EF will Automatically fill a null to those do not explicitly specified fields and i will get a exception.
i don't want modify database. what can i go with this? thank you
Edit:
my code like this... how make changes to it in your opinion?
[HttpPost]
public ActionResult Edit(Post_15 post)
{
if (ModelState.IsValid)
{
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
You must provide default values to your object (for example in constructor). EF doesn't play nicely with database default values. With default update EF always sends explicit value for each column. When you send explicit value, the default value the database is not used. If you don't set the value for property in the application, .NET default value is send to database.
Alternatively you must handle update in completely different way. You must explicitly set columns you are going to update to ensure that EF will not update other columns.
var entity = new YourEntity {
Id = 123,
ColumnToUpdate = "ABC"
};
objectContext.Attach(entity);
ObjectStateEntry entry = objectContext.ObjectStateManager.GetObjectStateEntry(entity);
entry.SetModifiedProperty("ColumnToUpdate");
objectContext.SaveChanges();
This code will update only ColumnToUpdate even if there are 20 other persisted properties.
Edit:
DbContext alternative:
var entity = new YourEntity {
Id = 123,
ColumnToUpdate = "ABC"
};
dbContext.Entities.Attach(entity);
DbStateEntry<Entity> entry = dbContext.Entry(entity);
entry.Property(e => e.ColumnToUpdate).IsModified = true;
dbContext.SaveChanges();
Side note: Only .NET 4.5 supports setting IsModified back to false.

Repository + UnitOfWork + EF Updating Master Record when detail records changed. (TotalAmount = Sum(Amount))

i'm trying to implement a Repository and UnitOfWork patterns using Entity Framework.
This is the scenario:
An user can add or modify detail records in a master-detail window and when hit "save" the added/modified records are sent to the server.
Then i perform a CreateOrUpdateMultiple().
CreateMultiple add the new records to the repository.
UpdateMultiple retrieve records that going to be updated.
After the two operations completes i need to update the master record with a sum(field) with all detail records. (With all i mean the existing ones that were not modified and the ones in memory)
This is what i have thought so far...
Being purist with repository pattern i should retrieve all detail records and then should mix in one list the existing records (modified or not) and the addded ones, and then do the sum operation, but what if the amount field of detail records is a database calculated field?
Read from database only records to be updated (thinking this will be faster because if i have 40 records and just 3 are modified and 2 added i will not read the entire set) and then somehow perform the update to the master record, but the problem is those records aren't yet in the database.
I have just one ObjectContext instance for all operations and i call SaveChanges() in my service to commit all in just one transaction.
What do you advice me to do? Or how do you archieve this kind of situation?
Thanks in advance
//Update
Here more technically described
The is what i have right now using transactionScope... and this is what i'm trying to avoid because of all the calls to database
//Service Layer
Method()
{
Method1.Invoke(masterRecordId, detaildRecords); //
}
//Business Layer
Method1(masterRecordId, detailRecords)
{
using(TransactionScope ts = new TransactionScope())
{
var recordsToUpdate = dal.RetrieveOnlyRecordsToUpdate();
//Update retrieved records with the values of recods comming from the client
dal.Update(recordsToUpdate); //ctx.ApplyChanges(); and ctx.SaveChanges();
dal.Add(recordsToAdd) //ctx.Add(detail records); and ctx.SaveChanges();
//Update master record TotalSum
dal.UpdateMasterRecord(masterRecordId); //Here is performed ctx.ExecuteStoredCommand("UPDATE MasterTable = SUM() WHERE MasterRecordId = {0}")...
Method2();
ts.Complete();
}
}
Method2(masterRecordId)
{
using(TransactionScope ts = new TransactionScope())
{
MasterRecord m = Retrieve(masteRecordId);
Notification notification = new Notification(){ ...assign properties..., m.TotalSum};
dal.Add(notification); //ctx.Add(notification); and ctx.SaveChanges();
ts.Complete();
}
}
This is what i want to do...
//Service Layer
Method()
{
Method1.Invoke(masterRecordId, detail records);
UnitOfWorkManager.Current.Commit(); //
}
//Business Layer
Metodo1(masterRecordId, detail records)
{
MasterRecord masterRecord = repository.Retrieve(masterRecordId);
var recordsToUpdate = repository.RetrieveOnlyRecordsToUpdate();
//Update retrieved records with the values of recods comming from the client
repository.Modify(recordsToUpdate);
repository.Add(recordsToAdd);
//Here i'm stuck and i'm thinking it should be something like this.
masterRecord.TotalSum = sum(detailRecords in memory + detail records in database); //
repository.Modify(masterRecord); //
or
//Another way somehow...
//Then keep going with the udpated master record
Method2(masterRecord);
}
}
Method2(masterRecord)
{
//Create notification
var notification = new Notification(){ ...properties.., masterRecord.TotalSum};
repository.Add(notification);
}
If you want to do it as transaction and call SaveChanges only once you must do it in your application before SaveChanges is called. So generally you must get sum before you do any change and modify the sum by updated values, inserted values and deleted values. Then you will set the new sum value into the master record. If you do it this way you will have unit of work.
Why other approaches are not so good.
Calculated field in database. This will require manually reloading master entity after the save operation because saving detail cannot reload changes in other entity. Moreover database logic will probably require trigger on detail table to modify sum in master table.
Updating master record after saving changes to details breaks unit of work.

Resources