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.
Related
I do have below function which taking more time for execution can someone help to write it properly,its getting while importing data for validation purpose
public void MapReferences(Company company, ISession session, List<Contract> contracts, List<Employee> employees, List<CompanySettingsMap> companies, List<Contact> contacts, IList<ImportEmployeeOrgProfileBatchItem> importedOrgProfileData, int lineNum = 2)
{
var dateConvertor = new DateConverter();
DateTime date;
foreach (var item in importedOrgProfileData)
{
item.CompanyId = company.Id;
item.LineNumber = lineNum;
item.CompanyReference = company?.Reference;
Employee employee = new Employee();
Contact contact = new Contact();
#region " Organisation Validation"
if (string.IsNullOrEmpty(item.Organisation))
{
item.CanContinue = false;
item.ErrorsList.Add("Invalid Organisation");
}
else
{
var allcontact = contacts.Where(x => x.Company.Id == company.Id && x.Reference.ToLower() == item.Organisation.ToLower()).ToList();
if (allcontact.Count > 1)
{
item.ErrorsList.Add("More than one contact found matching with organisation");
}
else
{
contact = allcontact.FirstOrDefault();
}
if (contact != null)
{
item.AgencyId = contact.Id;
item.AgencyReference = contact.Reference;
}
else
{
item.ErrorsList.Add("Contact not found matching with organisation");
item.CanContinue = false;
}
}
#endregion
if(string.IsNullOrEmpty(item.PostCode))
{
item.ErrorsList.Add("Postcode is required");
item.CanContinue = false;
}
#region " Employee Number Validation"
if (string.IsNullOrEmpty(item.EmployeeNumber) || item.EmployeeNumber.Length < 8)
{
item.CanContinue = false;
item.ErrorsList.Add("Invalid Employee Number");
}
else
{
string employeenumber = item.EmployeeNumber.Substring(0, 8);
employee = employees.Where(x => !string.IsNullOrEmpty(x.ExternalReference) && x.ExternalReference.ToLower().StartsWith(employeenumber.ToLower())).FirstOrDefault();
if (employee != null)
{
item.EmployeeId = employee.Id;
item.EmployeeExternalRef = employee.ExternalReference;
if (company.IsPayrollEnabled && employee.PayrollGroup?.Id != null)
{
item.PayrollGroupId = employee.PayrollGroup?.Id;
var payrollGroup = session.Query<PayrollGroup>().Where(x => x.Id == employee.PayrollGroup.Id).FirstOrDefault();
if (payrollGroup != null)
{
item.Payroll = payrollGroup.Description.ToString();
}
}
}
else
{
item.StarterDeclaration = Interfaces.HMRC.StarterDeclaration.OnlyJob;
item.TaxCode = session.Query<PayeSetting>().Single(x => x.Year == GovernmentTaxYearEndDate(DateTime.Today).Year).DefaultTaxCode;
item.EmployeeExternalRef = item.EmployeeNumber;
item.ChangeLogList.Add("Employee " + item.EmployeeNumber + " will be created");
item.CanContinue = true;
}
}
#endregion
#region " Validate Contract(Assignment number) "
if (string.IsNullOrEmpty(item.ContractNumber))
{
item.CanContinue = false;
item.ErrorsList.Add("Invalid Contract Number");
}
else
{
if (dateConvertor.TryConvertFromString(item.ContractStartDateString, out date))
{
item.ContractStartDate = date;
}
if (dateConvertor.TryConvertFromString(item.ContractEndDateString, out date))
{
item.ContractEndDate = date;
}
var contract = contracts.Where(x => !string.IsNullOrEmpty(x.ContractReference) && x.ContractReference.ToLower() == item.ContractNumber.ToLower()).FirstOrDefault();
if (employee == null && contract != null)
{
item.ContractReference = contract.ContractReference;
item.ErrorsList.Add("Contract can not be created because contract with reference " + contract.ContractReference + " is already assigned to other employee");
item.CanContinue = false;
}
else if (contract != null)
{
if (contract.Employee.Id == employee.Id)
{
item.ContractId = contract.Id;
item.ContractReference = contract.ContractReference;
}
else
{
item.ErrorsList.Add("Contract with reference " + contract.ContractReference + " is already assigned to other employee");
item.CanContinue = false;
}
}
else
{
item.ContractReference = item.ContractNumber;
if (contact == null)
{
item.ErrorsList.Add("Contract can not be created automatically because matching contact not found");
item.CanContinue = false;
}
else
{
item.ChangeLogList.Add("Contract " + item.ContractNumber + " will be created");
}
}
}
#endregion
#region " Parse and Assign Dates to date fields "
if (dateConvertor.TryConvertFromString(item.StartDateInPositionString, out date))
{
item.StartDateInPosition = date;
}
if (dateConvertor.TryConvertFromString(item.IncrementalDateString, out date))
{
item.IncrementalDate = date;
}
if (dateConvertor.TryConvertFromString(item.FixedTermEndDateString, out date))
{
item.FixedTermEndDate = date;
}
if (dateConvertor.TryConvertFromString(item.WtrOptOutDateString, out date))
{
item.WtrOptOutDate = date;
}
if (dateConvertor.TryConvertFromString(item.AdjustedServiceDateString, out date))
{
item.AdjustedServiceDate = date;
}
if (dateConvertor.TryConvertFromString(item.NHSEntryDateString, out date))
{
item.NHSEntryDate = date;
}
if (dateConvertor.TryConvertFromString(item.BirthDateString, out date))
{
item.BirthDate = date;
}
if (dateConvertor.TryConvertFromString(item.DateFirstHiredString, out date))
{
item.DateFirstHired = date;
}
else if (!item.EmployeeId.HasValue)
{
item.DateFirstHired = DateTime.Today.Date;
}
#endregion
if (!string.IsNullOrEmpty(item.Title))
{
item.Title = item.Title.Replace(".", "");
}
if (string.IsNullOrEmpty(item.MaritalStatus))
{
item.MaritalStatus = "U";
}
item.Payroll = string.Empty;
lineNum++;
item.Errors = item.ErrorsList.Count > 0 ? String.Join("|", item.ErrorsList.Distinct()) : string.Empty;
item.ChangeLog = item.ChangeLogList.Count > 0 ? String.Join("|", item.ChangeLogList) : string.Empty;
}
}
A good rule of thumb is that if you have copy/pasted code then you should have put it in a function, you could make one function for the date checking then call that, a lot of compilers and translators will then just hold that little bit in memory and repeatedly call it rather than all the lines you have there.
for the sake of readable code, maybe each region should be a separate function?
Shift your temp employee and contact object declarations outside the loop, as it is you have a memory declaration and memory assignation in each loop, moving it outside means you just have the assignation inside the loop (the parser/translator should do this automatically in c# but not always)
Shift everything that is not unique to that particular item to outside of the loop, the taxcode year for example means for every item that hits that else conditional then you are doing a linq query. Incidentally I have noticed great speed and memory gains to be made if you use for loops instead of linq, but they are less readable.
Item.CanContinue isn't used anywhere, maybe each object could handle it's own validation or you could have a static function that checks an object for issues and adds the issues to the list.
one example:
bool chkStringNotNull(string data, ref item, string ErrorMsg)
{
if(String.IsNullOrEmpty(data)) {
item.ErrorsList.Add(ErrorMsg);
return false;
}
return true;
}
Of course you would need to refactor to use item as a ref.
I am using the NEST (c#) client to communicate with Elasticsearch. I am using the suggest API to implement autocomplete in my site, here is my query code sample
var completionResult = client.Search(
body => body
.Type("myProject")
.Size(5)
.Fields("title","tags","control","platform")
.SuggestGlobalText(searchText)
.SuggestCompletion("SuggestCompletionResult", sfc => sfc
.OnField("control.suggestControl"))
.SuggestPhrase("SuggestPhraseResult", sfp => sfp
.OnField("control.suggestControl"))
);
i need to get final result as List<SuggestionList> and my suggestion list class is
public class SuggestionList
{
public string Text { get; set; }
}
the operation i performed to convert the result into List<SuggestionList> is
List<SuggestionList> SuggestResultSet = new List<SuggestionList>();
if (completionResult != null)
{
if (completionResult.Suggest != null && completionResult.Suggest.Count > 0)
{
var suggestionList = completionResult.Suggest.ToList();
if (suggestionList != null && suggestionList.Count > 0)
{
if (suggestionList[0].Value.ToList().Count() != 0 && suggestionList[0].Value.ToList()[0].Options.ToList().Count > 0)
{
foreach (var text in suggestionList[0].Value.ToList()[0].Options.ToList())
{
SuggestResultSet.Add(new SuggestionList { Text = text.Text });
}
}
if (suggestionList[1].Value.ToList().Count() != 0 && suggestionList[1].Value.ToList()[0].Options.ToList().Count > 0)
{
foreach (var text in suggestionList[1].Value.ToList()[0].Options.ToList())
{
SuggestResultSet.Add(new SuggestionList { Text = text.Text });
}
}
}
}
}
it take longer time to get final result, is there any way to do it without affecting performance
I think you have over complicated your conversion process, nesting is high. Bearing in mind this isn't compiled and is only pseudo.
List<SuggestionList> SuggestResultSet = new List<SuggestionList>();
if(completionResults != null)
{
foreach(var suggestion in completionResults.Suggest)
{
SuggestsResultSet.Add(new SuggestionList {Text = suggestion.Text });
}
}
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...
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();
}
I have banners on a site. When banner showed then I increment field in DB.
This is code:
public Banner GetBanner(CategoryBanner type)
{
var banners = Database.Banners.Where(b => b.IsPublish.Value &&
b.Category.Value == (int)type &&
b.PeriodShowCountAlready < b.PeriodShowCount || b.IsPublish.Value && b.Category.Value == (int)type &&
b.ShowNext < DateTime.Now);
var count = banners.Count();
if (count != 0)
{
var skip = new Random().Next(banners.Count() - 1);
Banner banner = banners.Skip(skip).FirstOrDefault();
if (banner != null)
{
UpdatePeriodShowCountAlready(banner); // problem is inside this method
if (banner.ShowStart == null)
UpdateShowStartAndEnd(banner);
return banner;
}
}
return null;
}
private void UpdatePeriodShowCountAlready(Banner banner)
{
try
{
if (banner != null)
{
banner.PeriodShowCountAlready++;
if (banner.PeriodShowCountAlready >= banner.PeriodShowCount && banner.ShowNext < DateTime.Now)
{
banner.PeriodShowCountAlready = 0;
banner.ShowStart = null;
banner.ShowNext = null;
}
Database.SubmitChanges();
}
}
catch (Exception ex)
{
ErrorLog.GetDefault(null).Log(new Error(ex));
}
}
And, I get the following error:
System.Data.Linq.ChangeConflictException
Row not found or changed.
This error is simple to reproduce:hold down the F5 is enough for a few seconds.
I understand why this error is occur, but how to rewrite my code properly?
Thanks.