Unit of Work patterns making sure data is saved - c#

I am using the Unit of Work patterns and want to a value back from the database to make sure it has updated the database successfully. Is there a way to do that?
UnitOfWork.Save();
public void Save()
{
try
{
Context.SubmitChanges();
}
catch (Exception dbEx)
{
Trace.WriteLine(
string.Format(
"Exception caught while saving unit of work: {0}", dbEx.StackTrace
));
throw;
}
}

When you call SubmitChanges(), a transaction is created.
All objects that have pending changes are ordered into a sequence of objects based on the dependencies between them. Objects whose changes depend on other objects are sequenced after their dependencies.
Immediately before any actual changes are transmitted, LINQ to SQL starts a transaction to encapsulate the series of individual commands.
Using the default conflict resolution mode (FailOnFirstConflict), the entirety of your changes fail to save when an error occurs in any one of them because the transaction encapsulating all your changes is rolled back.
That means that if your submission succeeds, you can be sure your unit of work was completed. You do not need to get a value back to determine whether or not your changes were saved.
You could also set the conflict resolution mode to ContinueOnConflict if you have changes that you know do not depend on each other and you want all changes to be attempted even if one or more fail.
Context.SubmitChanges(ConflictMode.ContinueOnConflict);

Related

Make sure that call api success and save myself success

Hello I found problem when I use ASP.NET MVC with EF and call Web API from other website(that have also use Entity Framework)
the problem is that
I want to make sure that both MVC SaveChanges() and Web API SaveChanges() succeed both together.
Here's my dream pseudo code
public ActionResult Operation()
{
Code Insert Update Delete....
bool testMvcSaveSuccess = db.TempSaveChanges(); //it does not have this command.
if(testMvcSaveSuccess == true)
{
bool isApiSuccess = CallApi(); //insert data to Other Web App
if(isApiSuccess == true)
{
db.SaveChanges(); //Real Save
}
}
}
From above code, if it doesn't have db.TempSaveChanges(), maybe Web API will be successful, but MVC SaveChanges() might fail.
So there is nothing like TempSaveChanges because there is something even better: Transactions.
Transaction is an IDisposable (can be used in a using block) and has methods like Commit and Rollback.
Small example:
private void TestTransaction()
{
var context = new MyContext(connectionString);
using (var transaction = context.Database.BeginTransaction())
{
// do CRUD stuff here
// here is your 'TempSaveChanges' execution
int changesCount = context.SaveChanges();
if (changesCount > 0)
// changes were made
{
// this will do the real db changes
transaction.Commit();
}
else
{
// no changes detected -> so do nothing
// could use 'transaction.Rollback();' since there are no changes, this should not be necessary
// using block will dispose transaction and with it all changes as well
}
}
}
I have extracted this example from my GitHub Exercise.EntityFramework repository. Feel free to Star/Clone/Fork...
Yes you can.
you need to overload the .Savechanges in the context class where it will be called first checked and then call the regular after.
Or create you own TempSaveChanges() in the context class call it then if successful call SaveChanges from it.
What you are referring to is known as atomicity: you want several operations to either all succeed, or none of them. In the context of a database you obtain this via transactions (if the database supports it). In your case however, you need a transaction which spans across two disjoint systems. A general-purpose (some special cases have simpler solutions) robust implementation of such a transaction would have certain requirements on the two systems, and also require additional persistence.
Basically, you need to be able to gracefully recover from a sudden stop at any point during the sequence. Each of the databases you are using are most likely ACID compliant, so you can count on each DB transaction to fulfill the atomicity requirement (they either succeed or fail). Therefore, all you need to worry about is the sequence of the two DB transactions. Your requirement on the two systems is a way to determine a posteriori whether or not some operation was performed.
Example process flow:
Operation begins
Generate unique transaction ID and persist (with request data)
Make changes to local DB and commit
Call external Web API
Flag transaction as completed (or delete it)
Operation ends
Recovery:
Get all pending (not completed) transactions from store
Check if expected change to local DB was made
Ask Web API if expected change was made
If none of the changes were made or both of the changes were made then the transaction is done: delete/flag it.
If one of the changes was made but not the other, then either revert the change that was made (revert transaction), or perform the change that was not (resume transaction) => then delete/flag it.
Now, as you can see it quickly gets complicated, specially if "determining if changes were made" is a non-trivial operation. What is a common solution to this is to use that unique transaction ID as a means of determining which data needs attention. But at this point it gets very application-specific and depends entirely on what the specific operations are. For certain applications, you can just re-run the entire operation (since you have the entire request data stored in the transaction) in the recovery step. Some special cases do not need to persist the transaction since there are other ways of achieving the same things etc.
ok so let's clarify things a bit.
you have an MVC app A1, with its own database D1
you then have an API, let's call it A2 with its own database D2.
you want some code in A1 which does a temp save in D1, then fires a call to A2 and if the response is successful then it saves the temp data from D1 in the right place this time.
based on your pseudo code, I would suggest you create a second table where you save your "temporary" data in D1. So your database has an extra table and the flow is like this:
first you save your A1 data in that table, you then call A2, data gets saved in D2, A1 receives the confirmation and calls a method which moves the data from the second table to where it should be.
Scenarios to consider:
Saving the temp data in D1 works, but the call to A2 fails. you now clear the orphan data with a batch job or simply call something that deletes it when the call to A2 fails.
The call to A2 succeeds and the call to D1 fails, so now you have temp data in D1 which has failed to move to the right table. You could add a flag to the second table against each row, which indicates that the second call to A2 succeeded so this data needs to move in the right place, when possible. You can have a service here which runs periodically and if it finds any data with the flag set to true then it moves the data to the right place.
There are other ways to deal with scenarios like this. You could use a queue system to manage this. Each row of data becomes a message, you assign it a unique id, a GUID, that is basically a CorrelationID and it's the same in both systems. Even if one system goes down, when it comes back up the data will be saved and all is good in the world and because of the common id you can always link it up properly.

Should I call SaveChanges once or after each change?

I need to make several changes in my database in my controller.
foreach (var valueStream in model.ListValueStream)
{
ValueStreamProduct vsp = new ValueStreamProduct(valueStream.Id, product.Id);
db.ValueStreamProduct.Add(vsp);
}
db.SaveChanges();
Should I call SaveChanges at the end or each time I make changes?
It depends.
With each change - If you want each save to run in its own transaction and be independent of other changes then run the save in the loop or after you make a change. Note that if there is a failure later in the code then the changes that have already occurred are persisted and will not be rolled back. This also has a higher performance cost as you are making more round trips to the data store. There are situations which could warrant this use though, here are 2 quick examples:
You want to track progress of long running action back to the data store and include changes up until that point.
You want to save in batches for large chunks of data that the code is processing and the code knows how to pick up an action after the last save point in the event of failure.
After all changes - If you want more performance and you want all saves to either pass or fail and be rolled back if there is any failure then run them at the end outside the loop or at the end of the code block. Now if there is a failure in the code (anywhere before or on the save changes call) no changes will be persisted to the store. In most situations this is desirable behavior as it ensures a good state for your data store. More frequently than not this is probably what you want your code to do.
It depends, on your requirement
Requirement 1) three table are independent.
public ActionResult Create()
{
db.ValueStreamProduct.Add(vsp);
db.tbl.Add(tbl2);
db.tbl.Add(tbl3);
// only one time you can call savechanges()
db.SaveChanges();
}
Requirement 2) ValueStreamProduct table Id is necessary for tbl2.
But, you need to get your last inserted record's Id for second table. code like this
public ActionResult Create()
{
db.ValueStreamProduct.Add(vsp);
db.SaveChanges();
// getting last inserted record's Id from ValueStreamProduct table.
tbl2.Column = vsp.Id
db.tbl.Add(tbl2);
db.tbl.Add(tbl3);
db.SaveChanges();
}
At the end, all the bunched up changes will get saved with fewer trips to the db and less overhead

best way to catch database constraint errors

I am calling a stored procedure that inserts data in to a sql server database from c#. I have a number of constraints on the table such as unique column etc. At present I have the following code:
try
{
// inset data
}
catch (SqlException ex)
{
if (ex.Message.ToLower().Contains("duplicate key"))
{
if (ex.Message.ToLower().Contains("url"))
{
return 1;
}
if (ex.Message.ToLower().Contains("email"))
{
return 2;
}
}
return 3;
}
Is it better practise to check if column is unique etc before inserting the data in C#, or in store procedure or let an exception occur and handle like above? I am not a fan of the above but looking for best practise in this area.
I view database constraints as a last resort kind of thing. (I.e. by all means they should be present in your schema as a backup way of maintaining data integrity.) But I'd say the data should really be valid before you try to save it in the database. If for no other reason, then because providing feedback about invalid input is a UI concern, and a data validity error really shouldn't bubble up and down the entire tier stack every single time.
Furthermore, there are many sorts of assertions you want to make about the shape of your data that can't be expressed using constraints easily. (E.g. state transitions of an order. "An order can only go to SHIPPED from PAID" or more complex scenarios.) That is, you'd need to use involving procedural-language based checks, ones that duplicate even more of your business logic, and then have those report some sort of error code as well, and include yet more complexity in your app just for the sake of doing all your data validation in the schema definition.
Validation is inherently hard to place in an app since it concerns both the UI and is coupled to the model schema, but I veer on the side of doing it near the UI.
I see two questions here, and here's my take...
Are database constraints good? For large systems they're indepensible. Most large systems have more than one front end, and not always in compatible languages where middle-tier or UI data-checking logic can be shared. They may also have batch processes in Transact-SQL or PL/SQL only. It's fine to duplicate the checking on the front end, but in a multi-user app the only way to truly check uniqueness is to insert the record and see what the database says. Same with foreign key constraints - you don't truly know until you try to insert/update/delete.
Should exceptions be allowed to throw, or should return values be substituted? Here's the code from the question:
try
{
// inset data
}
catch (SqlException ex)
{
if (ex.Message.ToLower().Contains("duplicate key"))
{
if (ex.Message.ToLower().Contains("url"))
{
return 1; // Sure, that's one good way to do it
}
if (ex.Message.ToLower().Contains("email"))
{
return 2; // Sure, that's one good way to do it
}
}
return 3; // EVIL! Or at least quasi-evil :)
}
If you can guarantee that the calling program will actually act based on the return value, I think the return 1 and return 2 are best left to your judgement. I prefer to rethrow a custom exception for cases like this (for example DuplicateEmailException) but that's just me - the return values will do the trick too. After all, consumer classes can ignore exceptions just as easily as they can ignore return values.
I'm against the return 3. This means there was an unexpected exception (database down, bad connection, whatever). Here you have an unspecified error, and the only diagnostic information you have is this: "3". Imagine posting a question on SO that says I tried to insert a row but the system said '3'. Please advise. It would be closed within seconds :)
If you don't know how to handle an exception in the data class, there's no way a consumer of the data class can handle it. At this point you're pretty much hosed so I say log the error, then exit as gracefully as possible with an "Unexpected error" message.
I know I ranted a bit about the unexpected exception, but I've handled too many support incidents where the programmer just sequelched database exceptions, and when something unexpected came up the app either failed silently or failed downstream, leaving zero diagnostic information. Very naughty.
I would prefer a stored procedure that checks for potential violations before just throwing the data at SQL Server and letting the constraint bubble up an error. The reasons for this are performance-related:
Performance impact of different error handling techniques
Checking for potential constraint violations before entering SQL Server TRY and CATCH logic
Some people will advocate that constraints at the database layer are unnecessary since your program can do everything. The reason I wouldn't rely solely on your C# program to detect duplicates is that people will find ways to affect the data without going through your C# program. You may introduce other programs later. You may have people writing their own scripts or interacting with the database directly. Do you really want to leave the table unprotected because they don't honor your business rules? And I don't think the C# program should just throw data at the table and hope for the best, either.
If your business rules change, do you really want to have to re-compile your app (or all of multiple apps)? I guess that depends on how well-protected your database is and how likely/often your business rules are to change.
I did something like this:
public class SqlExceptionHelper
{
public SqlExceptionHelper(SqlException sqlException)
{
// Do Nothing.
}
public static string GetSqlDescription(SqlException sqlException)
{
switch (sqlException.Number)
{
case 21:
return "Fatal Error Occurred: Error Code 21.";
case 53:
return "Error in Establishing a Database Connection: 53.";
default
return ("Unexpected Error: " + sqlException.Message.ToString());
}
}
}
Which allows it to be reusable, and it will allow you to get the Error Codes from SQL.
Then just implement:
public class SiteHandler : ISiteHandler
{
public string InsertDataToDatabase(Handler siteInfo)
{
try
{
// Open Database Connection, Run Commands, Some additional Checks.
}
catch(SqlException exception)
{
SqlExceptionHelper errorCompare = new SqlExceptionHelper(exception);
return errorCompare.ToString();
}
}
}
Then it is providing some specific errors for common occurrences. But as mentioned above; you really should ensure that you've tested your data before you just input it into your database. That way no mismatched constraints surface or exists.
Hope it points you in a good direction.
Depends on what you're trying to do. Some things to think about:
Where do you want to handle your error? I would recommend as close to the data as possible.
Who do you want to know about the error? Does your user need to know that 'you've already used that ID'...?
etc.
Also -- constraints can be good -- I don't 100% agree with millimoose's answer on that point -- I mean, I do in the should be this way / better performance ideal -- but practically speaking, if you don't have control over your developers / qc, and especially when it comes to enforcing rules that could blow your database up (or otherwise, break dependent objects like reports, etc. if a duplicate key were to turn-up somewhere, you need some barrier against (for example) the duplicate key entry.

Can Someone Explain This MSDN Code To Me In English?

This is concurrency related. So the SubmitChanges() fails, and a ChangeConflictException is thrown. For each ObjectChangeConflict in db.ChangeConflicts, its Resolve is set to RefreshMode.OverwriteCurrentValues? What does this mean?
http://msdn.microsoft.com/en-us/library/bb399354.aspx
Northwnd db = new Northwnd("...");
try
{
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
Console.WriteLine(e.Message);
foreach (ObjectChangeConflict occ in db.ChangeConflicts)
{
// All database values overwrite current values.
occ.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
I added some comments to the code, see if it helps:
Northwnd db = new Northwnd("...");
try
{
// here we attempt to submit changes for the database
// The ContinueOnConflict specifies that all updates to the
// database should be tried, and that concurrency conflicts
// should be accumulated and returned at the end of the process.
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
// we got a change conflict, so we need to process it
Console.WriteLine(e.Message);
// There may be many change conflicts (if multiple DB tables were
// affected, for example), so we need to loop over each
// conflict and resolve it.
foreach (ObjectChangeConflict occ in db.ChangeConflicts)
{
// To resolve each conflict, we call
// ObjectChangeConflict.Resolve, and we pass in OverWriteCurrentValues
// so that the current values will be overwritten with the values
// from the database
occ.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
First, you must understand that LinqToSql tracks two states for each database row. The original state and the current state. Original state is what the datacontext thinks is in the database. Current state has your in-memory modifications.
Second, LinqToSql uses optimistic concurrency to perform updates. When SubmitChanges is called, the datacontext sends the original state (as a filter) along with the current state into the database. If no records are modified (because the database's record no longer matches the original state), then a ChangeConflictException is raised.
Third, to resolve a change conflict, you must overwrite the original state so the optimistic concurrency filter can locate the record. Then you have to decide what to do with the current state... You can abandon your modifications (that's what the posted code does), which will result in no change to the record, but you are ready to move on with the current database values in your app.
I think it means that if it detects a conflict, see this under computing science, then it goes into the catch. Within there it goes through each of the conflicts (the foreach loop) and resets the values to what they were before the change tried to occur.
Apparently, any changes you've done to the objects are to be thrown out, since somebody else has stolen a march on you and updated the database while you were busy. In optimistic concurrency, dropping the changes is the only possible automated solution. However, the user probably isn't going to be too happy if they spent any time on inputting the discarded data.
The conflict is propabely caused by the fact that the object in your datacontext (the object that stores and keeps changes etc in .net code) has other values then the ones in your db.
Let's say you load a person object from the db. One of the fields is firstname, firstname is S
oo. Now you have a copy of your record in the datacontext. You change some things and want to write the changes to the db, but when (LINQ? other orm) wants to write the changes to the DB, it notices that the firstname in the DB is already changed.
So someone/something has changed your record, you have kind of a "deadlock" (correct term?) then you have to define what is more important, your changes, or the changes that something/someone else made.
TO THE POINT !!! -> Refreshmode.overwirteCurrentValues Just refreshes the object in your datacontext, it RELOADS the object from the db so that you are working with the updated object.
I hope this was a little clear :)
grtz

how to use exceptions in this scenario?

I have a method which handles a set of records.This method,return true\false after processing.So,if all the records are processed(doing some db updates),will return true.Now,suppose after processing 1 record,some exception is thrown,should I write result=false(at the end of method result is returned) in catch block? And,allow processing of other records to be done?
Continuing to add data to the dbase when adding one record failed is almost always wrong. Records are very frequently related. They represent a set of transactions on a bank account. Or a batch of orders from a customer. Adding these with one of them missing is always a problem.
Not only do you give your client a huge problem coming up with a new batch that contains the single corrected record, you make it far too easy to allow somebody to just ignore the error. The kind of error that doesn't get discovered or causes problems until much later. Invariably with a huge cost associated with correcting the error.
When an error occurs, reject the entire batch. Keep the dbase in a proper state by using transactions. Use, say, SqlTransaction and call BeginTransaction() when you start. Call Commit() when everything worked, call Rollback() in your catch clause.
Your client can now go back to the sub-system that generates the records, make the correction and re-run your program. Your dbase will always contain a proper copy of that sub-system's data. And errors cannot be ignored.
How you handle this with exceptions will be determined very much by what you want to happen in the event of something going wrong. You could, as you say, just write result= false in your catch blocks, but this means you are simply saying to the calling function "Hey - some records were not processed - live with it...". That might be enough for you - it depends what you're trying to do.
At the very least though, I would want to also write the details of the exceptions away to a log. And if you don't have a method somewhere that takes an exception and writes away to a log, it's time to write one (or use a third party solution...)
Otherwise you are losing information that could be useful in determining why things failed...
Whether you process those records you can or throw everything out in the event of a problem is a design question that only you can answer - we don't have the context...
I think it could be something like that
int count = 0;
foreach( item in list)
{
try
{
//update DB
++count;
}
catch(Exception ex)
{
//log exception
}
if(count == list.Count)
return true;
else return false;
}
Another way
bool result = true;
foreach( item in list)
{
try
{
//update DB
}
catch(Exception ex)
{
//log exception
result = false;
}
return result;
}

Categories

Resources