I have a list of big records and I need to loop through each record, add some filter and calculation and add it to my another list. I think doing one by one is affecting the performance because it's taking like 12s to show 900 records.
I am unable to identify why it's taking too long. I used my chrome developer tool to identify where it's slow. Then I came to find out loading taking 0.2s, scripting taking 3s, rendering taking 3s, idle is 3s and others are two seconds.
Maybe I am using Entity Framework and DataTables is making it slow. Or maybe something wrong is with my query. Following is my code:
public ActionResult Index(int id, string language)
{
var All_Employees = from employee in db.Employees
.Include(x => x.Country).Include(x => x.Status)
where enployee.GenderId == id
select employee ;
var List = new List<EmployeeListViewModel>();
foreach(var Record in All_Employees.ToList()
.OrderByDescending(x=> ParseDate(x.JoiningDate)))
{
EmployeeListViewModel item = new EmployeeListViewModel();
item.Id = Record.Id;
item.Code = Record.Code;
if(Record.CountryId != null)
{
if(language == "en")
{
item.Country = Record.Country.NameE;
}
else
{
item.Country = Record.Country.NameA;
}
}
item.Date = Record.JoiningDate;
int WorkingDays = 0;
if(Record.JoiningDate != null)
{
DateTime Joining= Convert.ToDateTime(ParseDate(Record.Record.JoiningDate));
TimeSpan t = DateTime.Now.Date - Joining;
int Days = int.Parse(t.TotalDays.ToString());
if (Days > 0)
{
WorkingDays = Days;
}
}
item.Days = WorkingDays.ToString();
if (Record.StatusId != null)
{
if (language == "en")
{
item.Status = Record.Status.NameE;
}
else
{
item.Status = Record.Status.NameE;
}
}
List.Add(item);
}
return View(List);
}
Another reason could be I am converting my date:
private static DateTime? ParseDate(string dateString)
{
if(dateString != null)
{
return DateTime.ParseExact(dateString, "dd-MM-yyyy", CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.None);
}
else
{
return null;
}
}
I don't want to make date filed as DateTime in my database, due to some reasons.
What's the best way to improve performance in my current situation?
Too much casting is used here in your code and list is created twice. One way you can do code like below.
List<EmployeeListViewModel> lstData = EmployeeListViewModel.ToList();
for(int i = 0; i < lstData.Count; i++)
{
//Put logic here for required changes like Language and Date.
if(lstData[i].CountryId != null)
{
if(language == "en")
lstData[i].Country = lstData[i].Country.NameE;
else
lstData[i].Country = lstData[i].Country.NameA;
}
}
Try to reduce casting specially for string and date-time. Below is example.
int Days = int.Parse(t.TotalDays.ToString());
In above line t.TotalDays is always int type, no need to cast to string and int again.
Related
how I can update a single value for an already existing row in the db by only having a parameters that I want to add it to this attribute
here is my code for a trivial way but didnt work
public bool BuyBook(int BookId, int UserId, int BookPrice){
using (var ctx = new OnlineBooksEntities())
{
User updatedCustomer = (from c in ctx.Users
where c.UserId == UserId
select c).FirstOrDefault();
updatedCustomer.Balance = BookPrice;
ctx.SaveChanges();
}
this.DeleteBook(BookId);
return true;
}
Add an sql query to the method solves the update aim
public bool BuyBook(int BookId, int UserId, int BookPrice)
{
try
{
using (var ctx = new OnlineBooksEntities())
{
User user = ctx.Users.Where(x => x.UserId == UserId).FirstOrDefault();
BookPrice = (int)user.Balance + BookPrice;
int noOfRowUpdated =
ctx.Database.ExecuteSqlCommand("Update Users set Balance = "+BookPrice+ " where UserId ="+UserId);
}
Updating basically means changing an existing row's value. Since you mentioned EF, you can do this by retrieving the object, changing its value, and saving it back. Thus you can do something like this:
using (var db = new MyContextDB())
{
var result = db.Books.SingleOrDefault(b => b.BookPrice == bookPrice);
if (result != null)
{
result.SomeValue = "Your new value here";
db.SaveChanges();
}
}
My below view code in View is below
#{
ViewBag.Title = "Student Dashboard";
var StudentRequestTimedt = ViewBag.StudentRequestTime as DataTable;
if (StudentRequestTimedt != null)
{
var StudentRequestTime = StudentRequestTimedt.AsEnumerable().Select(t => new
{
StudentRequestId = t.Field<int>("StudentRequestId"),
FromTime = t.Field<string>("FromTime"),
ToTime = t.Field<string>("ToTime"),
}).ToList();
}
else
{ var StudentRequestTime = ""; }
}
if (StudentRequestTime != "")
{
var StudentRequestTimecount = StudentRequestTime.Where(d => d.StudentRequestId == StudentRequestId).ToList();
}
On writting this I am getting error as StudentRequestTime doesnot exist in the current context.
This issue comes in case I am returning ViewBag.StudentRequestTime as null from controller side
My controller side code is as
if (GetData.Tables[1].Rows.Count > 0 && GetData.Tables[0].Rows.Count > 0)
{
ViewBag.StudentRequestTime = GetData.Tables[1];
}
else
{
ViewBag.StudentRequestTime = null;
}
return View();
Please Also review this below image, Here I am getting data in multiple viewbag in this case how can I manage? var StudentRequestTime is null or empty
How can I handle this issue ?
Updated code resolved my issue
Old code of controller
if (GetData.Tables[1].Rows.Count > 0 && GetData.Tables[0].Rows.Count > 0)
{
ViewBag.StudentRequestTime = GetData.Tables[1];
}
else
{
ViewBag.StudentRequestTime = null;
}
return View();
New Code of controller
ViewBag.StudentRequestTime = GetData.Tables[1];
On ViewSide
Consider this example:
if (eyeColor == EyeColor.Green)
{
// greenEyeColorFound has been declared *in this if statement*,
// so it only exists *within this if statement*
var greenEyeColorFound = true;
}
// this will fail. greenEyeColorFound was declared *in the first if statement*,
// how can the if statement below be aware of it's existence?
if (greenEyeColorFound == true)
{
Debug.WriteLine("Found a person with green eyes!");
}
greenEyeColorFound is locally scoped to the first if statement. Only code within that if statement can be aware of it's existence.
To get my example to work, greenEyeColorFound should be accessible by both ifs, which can be achieved by placing it's declaration outside of both ifs:
// this is now declared *outside* of the two if statements,
// so both are now aware of it and can access it's value.
var greenEyeColorFound = false;
if (eyeColor == EyeColor.Green)
{
greenEyeColorFound = true;
}
// presto, this now works
if (greenEyeColorFound == true)
{
Debug.WriteLine("Found a person with green eyes!");
}
This is the exact issue you are having with StudentRequestTime. Declare it once outside of the ifs, then just set it's value in your if/else statements.
Since we're at it, I wouldn't use ViewBag at all, let alone have it carry DataTables over to the Razor side. I would use viewmodels (read "Accessing Your Model's Data from a Controller" over at Microsoft ASP.NET MVC docs to see how this works, in particular section "Strongly Typed Models and the #model Keyword") which are much cleaner and maintainable.
You can easily refactor your existing code to use viewmodels using the steps below:
1) Create a class, let's name it StudentRequestTimeViewModel:
public class StudentRequestTimeViewModel
{
public int StudentRequestId { get; set; }
public string FromTime { get; set; }
public string ToTime { get; set; }
}
2) In your controller, populate a List<StudentRequestTimeViewModel>:
var studentRequestTimes = new List<StudentRequestTimeViewModel>();
if (GetData.Tables[1].Rows.Count > 0 && GetData.Tables[0].Rows.Count > 0)
{
// populate studentRequestTimes here
}
// return the view, passing in studentRequestTimes as our model
return View(studentRequestTimes);
3) Your Razor then becomes:
/* your model is declared as "#model",
but is accessed as "Model". */
#model List<StudentRequestTimeViewModel>
#if (Model != null && Model.Count > 0)
{
/* your List<StudentRequestTimeViewModel> Model is not null or empty */
foreach(var studentRequestTime in Model)
{
<p>Student with ID #studentRequestTime.StudentRequestId is here.</p>
}
}
else
{
/* your List<StudentRequestTimeViewModel> Model is null or empty */
}
I have a problem when deleting many nodes.
I can delete them if I select nodes like this:
But if I do something like this, I cannot delete them:
My Code:
public boolean remove(ProductNode<E> data) {
if (isEmpty()) {
throw new NoSuchElementException();
}
for (ProductNode<E> current = this.head; current != null; current = current.next) {
ProductNode<E> pre = current.prev;
ProductNode<E> next = current.next;
if (data != null) {
if (current.data.equals(data.data)) {
if (pre == null) {
head = next;
current.next = null;
} else {
if (next != null) {
next.prev = pre;
}
}
if (next == null) {
pre.next = null;
current.prev = null;
tail = pre;
} else {
if (pre != null) {
pre.next = next;
}
}
}
}
}
size--;
return false;
}
Search node
public ProductNode<E> search(E data) {
for (ProductNode<E> current = this.head; current != null; current = current.next) {
if (current.data.equals(data)) {
return current;
}
}
return null;
}
Remove
public void remove(E e) {
remove(search(e));
}
Delete:
for(Tab_Product p : remove_list){
List_Products.list_products.remove(p);
}
Your remove function (ProductNode data), is a bit complicated and may be affecting your code's ability to delete multiple nodes. In the case of this remove function you do not need traverse the whole data set. If you already have a reference to the node you can just directly modify the list with it.
public boolean remove(ProductNode<E> data) {
if (isEmpty()) {
throw new NoSuchElementException();
}
ProductNode<E> pre = data.prev;
ProductNode<E> next = data.next;
//First remove the nodes references to its neighbors.
data.prev = null;
data.next = null;
// Now check the neighbors and update their references
// to remove all references to the deleted node.
if (pre != null) pre.next = next;
if (next != null) next.prev = pre;
if (data == head) { //This checks the actual memory address.
head = next;
}
size--;
}
Since you already have the ProductNode, you do not need to search the list. your search() function is already doing that for you. since you already have the node you just need to make its references to its neighbors null then you just have to access the neighbors (if there are any) and make their old references skip over the deleted node.
I noticed a few reference errors where a deleted node was not getting completely removed from the list but i will not mention them because this delete function is rather complicated. Try simplifying the delete function and then see what your results are.
It also might be helpful if you show us the structure of the List_Products object.
Additionally you should verify that the data you select in the UI is getting passed correctly. This could be a UI bug.
// Inside an action result
tp = dbContext.tp.Single(x => ...);
foreach (Sample sample in tp.samples)
{
if (sample.SampleStatusId == 1)
changeSamplestatus(sample, 2, now); //change samples to on hold
}
dbContext.SaveChanges();
public void changeSamplestatus(Sample sample, int sampleStatus, DateTime now)
{
sample.SampleHistory.Add(new SampleHistory
{
OldStatus = sample.SampleStatusId,
NewStatus = sampleStatus,
});
sample.SampleStatusId = sampleStatus;
}
I have an entity (sample) that I would like to change it status.
I am calling a function to do so, but the entity doesn't get modified (but it is creating a new row in history table with the correct FK).
It doesn't throw any errors when SaveChanges is called. It just doesn't modify the entity.
You can try:
//INSIDE AN ACTION RESULT
var tp = dbContext.tp.SingleOrDefault(x => ...);
if (tp != null)
{
foreach (Sample sample in tp.samples)
{
if (sample.SampleStatusId == 1)
changeSamplestatus(sample, 2, DateTime.Now);
}
int flag = dbContext.SaveChanges();
if (flag > 0)
{
// update successful
}
}
public void changeSamplestatus(Sample sample, int sampleStatus, DateTime now)
{
//sample.SampleHistory.Add(new SampleHistory
//{
// OldStatus = sample.SampleStatusId,
// NewStatus = sampleStatus,
//});
sample.SampleStatusId = sampleStatus;
}
Don't use Single for this case, because it would throw exception if no result was found or there were more than 1 result. Use SingleOrDefault or FirstOrDefault instead.
You can try this . I hope thiw will work . The Idea is to get the history records first in the context and then update the propterties and set state to mofifed . Please try I didnt tested it but it should work.
public void changeSamplestatus(Sample sample, int sampleStatus, DateTime now)
{
var historyRecordToUpdate = db.SampleHistory.FirstOrDefault(h=>h.id == sampleHistoryId )
if(historyRecordToUpdate !=null )
{
db.Entry(sample).State= EntityState.Modified;
sample.SampleStatusId = sampleStatus;
}
}
running this code:
public bool CheckTime(DateTime date, int UserID, int TotalTimeMin)
{
using (var context = new myDB())
{
var assginments = from c in context.Assignments.Where(x=>(x.AssignmentDateTime < date && x.AssignmentDateTime.Value.AddMinutes(TotalTimeMin) > date) ||
(x.AssignmentDateTime < date.AddMinutes(TotalTimeMin))) select c;
if(assginments != null) return false;
else return true;
}
}
I get this error.
LINQ to Entities does not recognize the method 'System.DateTime AddMinutes(Double)' method, and this method cannot be translated into a store expression.
TotalTimeMin is int. I am not sure what cause this:
AssignmentDateTime is DateTime? and maybe this is the problem ?
Use EntityFunctions.AddMinutes (requires EF 4):
public bool CheckTime(DateTime date, int UserID, int TotalTimeMin)
{
using (var context = new myDB())
{
var assginments = context.Assignments
.Where(x=>(x.AssignmentDateTime < date
&& EntityFunctions.AddMinutes(x.AssignmentDateTime,TotalTimeMin) > date)
|| (x.AssignmentDateTime < date.AddMinutes(TotalTimeMin)));
if(assginments != null) return false;
else return true;
}
}
Note that assignments will never be null (but it might be empty -- test assignments.Any()).