I'm using a timestamp column to check the concurrency in my entity. The exception is correctly thrown when data is not the same in 2 different contexts.
When such an exception occurs when saving, I call the following method to handle it:
public static void HandleOptimisticConcurrencyException(ObjectContext context, OptimisticConcurrencyException ex)
{
string msg = #"The data has changed while you were editing it.
If you save, your changes will override the previous ones.
If you don't, your changes will be lost.
Do you want to save your changes ?";
var ret = System.Windows.MessageBox.Show(msg, "Concurrency error...", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (ret == MessageBoxResult.Yes)
{
if (ex.StateEntries != null)
{
foreach (var item in ex.StateEntries)
{
context.Refresh(RefreshMode.ClientWins, item.Entity);
}
}
}
else
{
if (ex.StateEntries != null)
{
foreach (var item in ex.StateEntries)
{
context.Refresh(RefreshMode.StoreWins, item.Entity);
}
}
}
context.SaveChanges();
}
I checked, and the refresh is executed on each faulted entity.
However, the second SaveChanges() always rethrows an OptimisticConcurrencyException.
Am I doing something wrong ?
Thanks in advance
Edit
I've noticed that the problem arises because of a method call before the first SaveChanges()
try
{
this.UpdateFlags();
this.repository.Context.SaveChanges();
}
catch (OptimisticConcurrencyException ex)
{
ExceptionHelpers.HandleOptimisticConcurrencyException(this.repository.Context, ex);
}
If I comment out the UpdateFlags() call, I have no problem.
Here is the code for this method:
private void UpdateFlags()
{
DateTime now = DateTime.Now;
int masterId = (int)this.navigationContext.Item;
var master = this.repository.Context.Masters.Where(e => e.Id == masterId).FirstOrDefault();
foreach (var project in master.Projects)
{
// update flags for each project.
if (project.Dashboard == null)
{
project.Dashboard = new Dashboard();
}
var flags = project.Dashboard;
flags.ModifiedOn = now;
// Update DP flags
var dpFlag = (int)project.Tasks.Where(e => e.TaskDP != null)
.Select(e => this.CalculateCompletionStatus(e, now))
.DefaultIfEmpty(CompletionStatusType.Ok)
.Max();
flags.DP = dpFlag;
// Update TRS flags
var trsFlag = (int)project.Tasks.Where(e => e.TaskTRSs != null)
.Select(e => this.CalculateCompletionStatus(e, now))
.DefaultIfEmpty(CompletionStatusType.Ok)
.Max();
flags.TRS = trsFlag;
// Update REV flags
var revFlag = (int)project.Tasks.Where(e => e.TaskREV != null)
.Select(e => this.CalculateCompletionStatus(e, now))
.DefaultIfEmpty(CompletionStatusType.Ok)
.Max();
flags.REV = revFlag;
// Update DTP flags
var dtpFlag = (int)project.Tasks.Where(e => e.TaskDTP != null)
.Select(e => this.CalculateCompletionStatus(e, now))
.DefaultIfEmpty(CompletionStatusType.Ok)
.Max();
flags.DTP = dtpFlag;
// Update DEL flags
var delFlag = (int)project.Tasks.Where(e => e.TaskDEL != null)
.Select(e => this.CalculateCompletionStatus(e, now))
.DefaultIfEmpty(CompletionStatusType.Ok)
.Max();
flags.DEL = delFlag;
// Update FIN Flag
var finFlag = (int)project.SalesTasks.Select(e => this.CalculateCompletionStatus(e, now))
.DefaultIfEmpty(CompletionStatusType.Ok)
.Max();
flags.FIN = finFlag;
// Update Project flag
if (flags.REV == (int)CompletionStatusType.Client && project.DTPBeforeReview.HasValue && project.DTPBeforeReview.Value == false)
{
// Corner case : Review is late because of an external person (= grey) and DTP Before REV is not set
// => all moments after REV are not taken in account.
var projFlag = new List<int> { dpFlag, trsFlag, revFlag }.Max();
flags.ProjectStatus = projFlag;
}
else
{
var projFlag = new List<int> { dpFlag, trsFlag, revFlag, dtpFlag, delFlag, finFlag }.Max();
flags.ProjectStatus = projFlag;
}
}
}
However I don't see where the problem is, as this is made before the first SaveChanges()
Ok I think I found how to solve that.
The problem doesn't come from the first object who causes the first exception, but deeper in this object.
To solve that, I updated my method like this:
public static void HandleOptimisticConcurrencyException(ObjectContext context, OptimisticConcurrencyException ex)
{
string msg = #"The data has changed while you were editing it.
If you save, your changes will override the previous ones.
If you don't, your changes will be lost.
Do you want to save your changes ?";
var ret = System.Windows.MessageBox.Show(msg, "Concurrency error...", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (ret == MessageBoxResult.Yes)
{
if (ex.StateEntries != null)
{
foreach (var item in ex.StateEntries)
{
context.Refresh(RefreshMode.ClientWins, item.Entity);
}
}
}
else
{
if (ex.StateEntries != null)
{
foreach (var item in ex.StateEntries)
{
context.Refresh(RefreshMode.StoreWins, item.Entity);
}
}
}
do
{
try
{
context.SaveChanges();
break;
}
catch (OptimisticConcurrencyException ex2)
{
if (ret == MessageBoxResult.Yes)
{
foreach (var item in ex2.StateEntries)
{
context.Refresh(RefreshMode.ClientWins, item.Entity);
}
}
else
{
foreach (var item in ex2.StateEntries)
{
context.Refresh(RefreshMode.StoreWins, item.Entity);
}
}
}
}
while (true);
}
I'm open to any other better suggestion though...
Related
I set a background task on my application using hangfire. But the problem is on the local machine it works fine and the database changes work as well. On the web server, it also executes but can't make any changes to the database.
Here's the initiation code -
public IActionResult CornJobs()
{
CornExpression? corn = _context.Set<CornExpression>().AsNoTracking().FirstOrDefault();
if(corn.PayExpres == null)
{
RecurringJob.RemoveIfExists("Increase Payment");
}
else
{
RecurringJob.AddOrUpdate("Increase Payment", () => _students.IncreasePayment(), corn.PayExpres);
}
if (corn.SMSExpres == null)
{
RecurringJob.RemoveIfExists("Send Alert");
}
else
{
RecurringJob.AddOrUpdate("Send Alert", () => _students.SendDueAlert(), corn.SMSExpres);
}
return View(corn);
}
And here is the interface implementation
public bool IncreasePayment()
{
try
{
var students = _context.Set<Student>().AsNoTracking().Where(x => x.Status == 1 && (x.Batch1 == 1 || x.Batch2 == 1)).ToList();
foreach (var student in students)
{
if(GetMonthDifference(student.DateOfReg, DateTime.Now) == 0)
{
continue;
}
Due due = new()
{
StudentId = student.StudentId,
Recurring = DateTime.Now.ToString("MMMM, yyyy"),
Amount = student.Payment,
PreviousAmount = student.Due,
CurrentAmount = student.Due + student.Payment,
RecurredOn = DateTime.Now
};
student.TotalPayment += due.Amount;
student.Due += due.Amount;
_context.Update(student);
_context.Add(due);
}
_context.SaveChanges();
return true;
}
catch (Exception)
{
return false;
}
}
What mistake have I made here?
Thank you.
I have some LINQ to Object Query Code:
List<ePayDocumentOperation> additionalDocuments = new List<ePayDocumentOperation>();
try
{
additionalDocuments = (from op in possibleClientDocuments
let senderAccountID = GetSenderAccountID(con, op)
where Filter.Wallets.Contains(senderAccountID)
select op).ToList();
}
catch (Exception ex)
{
// some catcher
}
possibleClientDocuments object contains about 3 000 records. Not so much but the query freeze and I don't get result. I don't get any execeptions. I try to select code to try catch block but I don't see any exceptions and at the same time I don't get result too.
How to check the problem of query and why I don't getting result?
Thanks!
P.S.
private static long GetSenderAccountID(LavaPayEntities Con, ePayDocumentOperation operation)
{
long result = default(long);
// Payment
if (operation.OperationPatternID == Chart.Operations.PS_Payment)
{
var ipnRequest = Con.eIPNRequests.FirstOrDefault(ir => ir.OperationID == operation.ID);
if (ipnRequest == null) return result;
if (ipnRequest.ClientAccountID != null && ipnRequest.ClientAccountID != 0) return (long)ipnRequest.ClientAccountID;
var clientAccount = Con.eAccounts.FirstOrDefault(a => a.Email.Email == ipnRequest.ClientEmail);
if (clientAccount != null)
{
result = clientAccount.ID;
}
else
{
var client = ipnRequest.Client;
if (client != null)
{
clientAccount = client.Accounts.FirstOrDefault();
if (clientAccount != null)
{
result = clientAccount.ID;
}
}
}
}
// Other Operations
else
{
result = operation.SenderAccountID.HasValue ? operation.SenderAccountID.Value : 0;
}
return result;
}
i am trying to update a m-to-m relation with a ListBox. My entity-model looks like this:
I have a ListBox with Checkboxes where the user can decide which Player is in the league and which is not (IsSelected-Property). There are two problems: At first i can't check and then uncheck a Player (it won't be deleted). Second Problem: the first try, everything works and when i do the selection again, i get the following exception:
_innerException {"An error occurred while updating the entries. See the inner exception for details."} System.Exception {System.Data.Entity.Core.UpdateException}
_innerException {"Violation of PRIMARY KEY constraint 'PLID'. Cannot insert duplicate key in object 'dbo.PlayerLeague'. The duplicate key value is (2, 2).\r\nThe statement has been terminated."} System.Exception {System.Data.SqlClient.SqlException}
using (BettingLeagueEntities entities = new BettingLeagueEntities())
{
foreach (PlayerCheckBoxList p in this.PlayerList)
{
if(p.IsSelected == true)
{
PlayerLeague pl = new PlayerLeague();
pl.League = this.ActiveLeague;
pl.Player = p.ActivePlayer;
var local = entities.Set<Player>().Local.FirstOrDefault(x => x.PID == p.ActivePlayer.PID);
if(local != null)
{
entities.Entry(local).State = System.Data.Entity.EntityState.Detached;
}
var localLeague = entities.Set<League>().Local.FirstOrDefault(x => x.LID == this.ActiveLeague.LID);
if (localLeague != null)
{
entities.Entry(localLeague).State = System.Data.Entity.EntityState.Detached;
}
if (entities.Entry(p.ActivePlayer).State == System.Data.Entity.EntityState.Detached)
{
entities.Player.Add(p.ActivePlayer);
entities.Entry(p.ActivePlayer).State = System.Data.Entity.EntityState.Modified;
}
if (entities.Entry(this.ActiveLeague).State == System.Data.Entity.EntityState.Detached)
{
entities.League.Add(this.ActiveLeague);
entities.Entry(this.ActiveLeague).State = System.Data.Entity.EntityState.Modified;
}
if(p.ActivePlayer.PlayerLeague.All(x => x.LID != this.ActiveLeague.LID))
{
p.ActivePlayer.PlayerLeague.Add(pl);
this.ActiveLeague.PlayerLeague.Add(pl);
}
}
else
{
PlayerLeague local = entities.Set<PlayerLeague>().Local.FirstOrDefault(x => x.LID == this.ActiveLeague.LID && x.PID == p.ActivePlayer.PID);
if(local != null)
{
entities.PlayerLeague.Attach(local);
entities.PlayerLeague.Remove(local);
}
entities.SaveChanges();
}
}
entities.SaveChanges();
}
I have no clue how to solve this, do you have any suggestions?
I have it! I tried to comment a little bit to make it understandable.
The first problem was that i checked if my PlayerLeague already exists too lately. I moved this condition in my first if(statement).
The second error was, that in my else block, my statement to find a playerleague returned alsways null. Now i check if there is any entity and if this is true, i delete it.
using (BettingLeagueEntities entities = new BettingLeagueEntities())
{
foreach (PlayerCheckBoxList p in this.PlayerList)
{
// Check if the Player is seleceted and if the ActivePlayer has the Active League
if (p.IsSelected == true && p.ActivePlayer.PlayerLeague.All(x => x.LID != this.ActiveLeague.LID))
{
// Define the new PlayerLeague
PlayerLeague pl = new PlayerLeague {PID = p.ActivePlayer.PID, LID = this.ActiveLeague.LID};
var localPlayer = entities.Set<Player>().Local.FirstOrDefault(x => x.PID == p.ActivePlayer.PID);
if (localPlayer != null)
{
entities.Entry(localPlayer).State = System.Data.Entity.EntityState.Detached;
}
if (entities.Entry(p.ActivePlayer).State == System.Data.Entity.EntityState.Detached)
{
entities.Player.Add(p.ActivePlayer);
entities.Entry(p.ActivePlayer).State = System.Data.Entity.EntityState.Modified;
}
var localLeague = entities.Set<League>().Local.FirstOrDefault(x => x.LID == this.ActiveLeague.LID);
if (localLeague != null)
{
entities.Entry(localLeague).State = System.Data.Entity.EntityState.Detached;
}
if (entities.Entry(this.ActiveLeague).State == System.Data.Entity.EntityState.Detached)
{
entities.League.Add(this.ActiveLeague);
entities.Entry(this.ActiveLeague).State = System.Data.Entity.EntityState.Modified;
}
p.ActivePlayer.PlayerLeague.Add(pl);
this.ActiveLeague.PlayerLeague.Add(pl);
}
else
{
// Check if there is a PlayerLeague for this Player and league
bool hasPlayerLeague =
entities.PlayerLeague.Any(x => x.LID == this.ActiveLeague.LID && x.PID == p.ActivePlayer.PID);
if (hasPlayerLeague && p.IsSelected == false)
{
// Find PlayerLeague
PlayerLeague pl =
entities.PlayerLeague.FirstOrDefault(
x => x.LID == this.ActiveLeague.LID && x.PID == p.ActivePlayer.PID);
// Attach and Remove PlayerLeague
entities.PlayerLeague.Attach(pl);
entities.PlayerLeague.Remove(pl);
}
entities.SaveChanges();
}
}
}
Want to check if any records exist in ClientAccessCode table, if not return false...
if (!CheckAccessCodeExists())
{
Console.WriteLine("Client Access code does not exist");
throw new ConfigurationErrorsException("Client Access code does not exist");
}
private static bool CheckAccessCodeExists()
{
using (EPOSEntities db = new EPOSEntities())
{
ClientAccountAccess clientAccess = db.ClientAccountAccesses
.OrderByDescending(x => x.Id)
.Take(1)
.Single();
if (clientAccess != null)
{
return true;
}
return false;
}
}
//this is flagging sequence contains no elements, in the lamba expression, so how can I just return false then? some use of .Any() perhaps?
thanks
EDIT
Thats great thanks for the help guys il mark the answer now, also another query if I had
ClientAccountAccess clientAccess = db.ClientAccountAccesses
.OrderByDescending(x => x.Id)
.Take(1)
.Single();
if (clientAccess != null)
{
db.DeleteObject(clientAccess);
}
how can I refactor this to say something tidier like
if (db.ClientAccountAccesses.Any())
{
db.DeleteObject(//what does in here do I have to use above code to get record to delete?);
}
The problem is Single expects there to be at least one item in the collection, if it doesn't find 1 then it throws an exception. If it's possible for your collection to not have a record then you should be using SingleOrDefault - this will return the default value for the type you are working with, in your case this will return null.
ClientAccountAccess clientAccess = db.ClientAccountAccesses
.OrderByDescending(x => x.Id)
.Take(1)
.SingleOrDefault();
if (clientAccess != null)
{
db.DeleteObject(clientAccess);
}
private static bool CheckAccessCodeExists()
{
using (EPOSEntities db = new EPOSEntities())
{
var item = db.ClientAccountAccesses.FirstOrDefault();
if(item != null)
{
db.Remove(item);
db.SaveChanges();
return true;
}
return false;
}
}
private static bool CheckAccessCodeExists()
{
using (EPOSEntities db = new EPOSEntities())
{
var item = db.ClientAccountAccesses.FirstOrDefault();
if (item != null)
{
db.DeleteObject(item);
db.SaveChanges();
return true;
}
}
return false;
}
I am Using Linq to Entity MVC and when I am trying to delte records from database I am getting this Exception.
New transaction is not allowed because there are other threads running in the session.
My code:
if (Request.Form["Enroll"] != null)
{
string[] selected = Request.Form["Enroll"].Split(',');
if (selected != null)
{
if (selected.Count() != 0)
{
int k = 0;
foreach (var item in selected)
{
var TraineeId = Convert.ToInt32(item[k].ToString());
var sessionid = Convert.ToInt32(Session["user"].ToString());
var id = db.EnrollTrainee.Where(i => i.TraineeID == TraineeId
&& i.TrainerID == sessionid);
if (id != null)
{
foreach (var a in id)
{
//db.Database.Connection.Close();
EnrollTrainee delete = db.EnrollTrainee.Find(a.id);
db.EnrollTrainee.Remove(delete);
db.SaveChanges(); //Getting Exception Here
}
}
k++;
}
}
}
populatelistbox();
return View();
}
Please Help.!!!
Thanks in Advance.!!!
In my case, calling the SaveChanges() less often in nested loops solves the problem:
//produces error
foreach(...) {
foreach(...) {
...
db.SaveChanges();
} }
this is my solution
//does not produce error
foreach(...) {
foreach(...) {
...
}
}
db.SaveChanges();
Got a very good solution in this nice Blog.
Solution of my problem:-
if (Request.Form["Enroll"] != null)
{
string[] selected = Request.Form["Enroll"].Split(',');
if (selected != null)
{
if (selected.Count() != 0)
{
int k = 0;
foreach (var item in selected)
{
var TraineeId = Convert.ToInt32(item[k].ToString());
var sessionid = Convert.ToInt32(Session["user"].ToString());
var id = db.EnrollTrainee.Where(i => i.TraineeID == TraineeId
&& i.TrainerID == sessionid);
var idlist = id.ToArray<EnrollTrainee>();//Added New Line
if (idlist != null)
{
foreach (var a in idlist)
{
EnrollTrainee delete = db.EnrollTrainee.Find(a.id);
db.EnrollTrainee.Remove(delete);
db.SaveChanges();
}
}
k++;
}
}
}
populatelistbox();
return View();
}