c# Object properties is loading from cache - c#

in my win-form application, there is a method that combines some items that have been created previously, when the code is the first time to run, everything is fine, but in second and later runs combined items have the wrong length.
the code reads items from a SQL server using LINQ that has object type named "BetaData"
BetaData has a property named "Length" that is double.
I have another list that processed items is stored in name "PartList" of type "ModifiedPartList".
in method length property changes for some items, but nothing gets stored or saved on SQL.
this is the main method:
private List<ModifiedPartList> CombinePartList(ProgressBar Bar)
{
PartList.Clear();
List<BetaData> PartsinOrder = new List<BetaData>();
foreach (int view in Globals.Views)
{
List<int> OrdersInView = new List<int>();
foreach (Tuple<int, int> tuple in Globals.Orders)
{
if (tuple.Item1 == view)
{
if (!OrdersInView.Contains(tuple.Item2))
OrdersInView.Add(tuple.Item2);
}
}
if(OrdersInView.Count>0)
{
OrdersInView.Sort();
foreach (int order in OrdersInView)
{
//this is the section that problem occurs:
var parts = from BetaData in BetaContext.BetaDatas
where BetaData.ProjectName == Globals.ProjectName &&
BetaData.ProjectCode == Globals.ProjectCode &&
BetaData.ParentItem != Globals.ProjectName + "(" + Globals.ProjectCode + ")" &&
BetaData.View == view &&
BetaData.Order == order
select BetaData;
PartsinOrder.Clear();
PartsinOrder = parts.ToList();
foreach(BetaData part in PartsinOrder)
{
Bar.PerformStep();
}
}
}
PartsinOrder.Clear();
}
return PartList;
}
in the section that i have commented as problem location when the code is running for the second time, optimized length property is loaded to items instead of their original value from SQL. i cannot understand that because each time i read all items from SQL server.
the point is in this stage after that i ran the method for several times and getting the wrong results when i close the program and start it again, on first run results are true.
after selecting from SQL and converting it to list, i review items and their properties in list, and they are all true, but in foreach loop when each part comes into loop their Length property is wrong.

the issue was solved using this article and refreshing context after retrieving data from SQL

Related

Trying to get a COMPLETE list of AWS Route53 records. How to get more than the first 100?

I am trying to list records on route53 that we have but am failing to get more than the first 100 results! How can I list ALL of them? How can I also filter the results to list only those with a specific RecordType?
This is the code I tried running but I fail to get a complete list…:
string recordList = "";
int ii = 0;
ListResourceRecordSetsResponse result = r53client.ListResourceRecordSets(request);
System.Windows.Forms.MessageBox.Show(result.ListResourceRecordSetsResult.ResourceRecordSets.Count+" records!");
while (result.ListResourceRecordSetsResult.ResourceRecordSets.Count > 0)
{
foreach (var recordSet in result.ListResourceRecordSetsResult.ResourceRecordSets)
{
if (recordSet.Type == "CNAME")
{
foreach (var resourceRecord in recordSet.ResourceRecords)
{
recordList += resourceRecord.Value + "\n";
jj++;
// set first record to get next, as the last one we already got!
request.StartRecordName = resourceRecord.Value;
}
}
}
result = r53client.ListResourceRecordSets(request);
}
From Github: Can you get more than 100 ListResourceRecordSets:
If the response says IsTruncated is true, then you need to pass the values of NextRecordType, NextRecordName, and NextRecordIdentifier back to a new call.
From AWS Command-Line Interface (CLI) documentation for list-resource-record-sets:
To retrieve all the records in a HostedZone, first pause any processes making calls to ChangeResourceRecordSets. Initially call list-resource-record-sets without a Name and Type to get the first page of record sets. For subsequent calls, set Name and Type to the NextName and NextType values returned by the previous response.
From Class ListResourceRecordSetsRequest:
To retrieve all the records in a HostedZone, first pause any processes making calls to ChangeResourceRecordSets. Initially call ListResourceRecordSets without a Name and Type to get the first page of record sets. For subsequent calls, set Name and Type to the NextName and NextType values returned by the previous response.

Filtering items before adding to an array in c#

I'm just getting to grips with some c# after being thrown in at the deep end on a little scripting task.
I'm trying to amend some code that builds a drop-down box on a web page so that it contains a list of only four items, I'm not sure of the syntax required to achieve this but hoping you folks can help.
using (CoreBusinessLayerProxy proxy = CoreBusinessLayerProxy.CreateCoreBusinessLayerProxy(BusinessLayerExceptionHandler))
{
eventTypesTable = proxy.GetEventTypesTable();
}
eventTypes.Items.Add(new ListItem(Resources.CoreWebContent.WEBCODE_VB0_201, "All events"));
EventTypes.Add("All events", 0);
foreach (DataRow r in eventTypesTable.Rows)
{
eventTypes.Items.Add(r["Name"].ToString());
try
{
EventTypes.Add(r["Name"].ToString(), Int32.Parse(r["EventType"].ToString()));
}
catch { }
}
I'm trying to amend the above so that rather than adding all of the DataRow's from eventTypeTable.Rows it adds only a set of four hard-coded values which I suspect I need to pass during the foreach but I cannot for the life of me wrap my head around where or when I should be doing this in the loop.
(The joys of working on uncommented code)
Thanks!
Here's a rudimentary way to do this based on the Name field. If the Name is not one of "allow1", "allow2", "allow3" or "allow4", then it will continue. This moves to the next iteration in the foreach loop without executing the rest of the statement block for the current one.
foreach (DataRow r in eventTypesTable.Rows)
{
string name = r["Name"].ToString();
if ( name != "allow1" && name != "allow2" && name != "allow3" && name != "allow4" )
continue;
eventTypes.Items.Add(r["Name"].ToString());
try
{
EventTypes.Add(r["Name"].ToString(), Int32.Parse(r["EventType"].ToString()));
}
catch { }
}

How to retrieve keywords within thousands of records from SQL Server 2008 fast?

Using the query function of entity collection in C# and it takes a long time to load the related records back from SQL Server 2008. Is there any fast way to do this? This is the query function I use:
public void SearchProducts()
{
//Filter by search string array(searchArray)
List<string> prodId = new List<string>();
foreach (string src in searchArray)
{
StoreProductCollection prod = new StoreProductCollection();
prod.Query.Where(prod.Query.StptName.ToLower() == src.ToLower() && prod.Query.StptDeleted.IsNull());
prod.Query.Select(prod.Query.StptName, prod.Query.StptPrice, prod.Query.StptImage, prod.Query.StptStoreProductID);
// prod.Query.es.Top = 4;
prod.Query.Load();
if (prod.Count > 0)
{
foreach (StoreProduct stpt in prod)
{
if (!prodId.Contains(stpt.StptStoreProductID.ToString().Trim()))
{
prodId.Add(stpt.StptStoreProductID.ToString().Trim());
productObjectsList.Add(stpt);
}
}
}
}
You're hitting the database once per searchArray item, this is very wrong.
You might get better performance like this (have no way of testing it, give it a shot):
public void SearchProducts()
{
//Filter by search string array(searchArray)
List<string> prodId = new List<string>();
StoreProductCollection prod = new StoreProductCollection();
// Notice that your foreach() is gone
// replace this
// prod.Query.Where(prod.Query.StptName.ToLower() == src.ToLower() && prod.Query.StptDeleted.IsNull());
// with this (or something similar: point is, you should call .Load() exactly once)
prod.Query.where(prod.Query.StptDeleted.IsNull() && src.Any(srcArrayString => prod.Query.StptName.ToLower()==srcArrayString.ToLower());
prod.Query.Select(prod.Query.StptName, prod.Query.StptPrice, prod.Query.StptImage, prod.Query.StptStoreProductID);
// prod.Query.es.Top = 4;
prod.Query.Load();
// ... rest of your code follows.
}
Given List<string> searchArray containing lowered words :
public void SearchProducts()
{
//Filter by search string array(searchArray)
List<string> prodId = new List<string>();
StoreProductCollection prod = new StoreProductCollection();
prod.Query.Where(searchArray.Contains(prod.Query.StptName.ToLower()) && prod.Query.StptDeleted.IsNull());
prod.Query.Select(prod.Query.StptName, prod.Query.StptPrice, prod.Query.StptImage, prod.Query.StptStoreProductID);
// prod.Query.es.Top = 4;
prod.Query.Load();
if (prod.Count > 0)
{
foreach (StoreProduct stpt in prod)
{
if (!prodId.Contains(stpt.StptStoreProductID.ToString().Trim()))
{
prodId.Add(stpt.StptStoreProductID.ToString().Trim());
productObjectsList.Add(stpt);
}
}
}
}
This way you have only one query for all words.
First of all, put an index on StptName column.
Second, if you need even better performance, write a Stored Procedure in SQL, to do your querying, and map it with Entity Framework.
Let me know if you need explanation on how to do any of the above.
A couple more micro-optimizations you can do if you don't want to write a Stored Procedure:
Write src.ToLower() in a temporary varaible, and than compare prod.Query.StptName.ToLower() to it.
By default, SQL Server queries are case insensitive, so check if that's the case, and if so, you can get rid of the ToLower altogether. You can change case sensitivity through Collation.
EDIT:
To create an Index:
Open the table designer in SQL Server Managment Studio.
Right click anywhere and select Indexes/Keys.
Click Add.
Under Columns add StptName.
Under Is Unique specify whether StptName is unique or not.
Under type select "index".
That's all!
As for mapping stored procedures - here's a nice tutorial:
http://www.robbagby.com/entity-framework/entity-framework-modeling-select-stored-procedures/
(You can jump straight to the "Map in the Select Stored Procedure" Section).

Newbie performance issue with foreach ...need advice

This section simply reads from an excel spreadsheet. This part works fine with no performance issues.
IEnumerable<ImportViewModel> so=data.Select(row=>new ImportViewModel{
PersonId=(row.Field<string>("person_id")),
ValidationResult = ""
}).ToList();
Before I pass to a View I want to set ValidationResult so I have this piece of code. If I comment this out the model is passed to the view quickly. When I use the foreach it will take over a minute. If I hardcode a value for item.PersonId then it runs quickly. I know I'm doing something wrong, just not sure where to start and what the best practice is that I should be following.
foreach (var item in so)
{
if (db.Entity.Any(w => w.ID == item.PersonId))
{
item.ValidationResult = "Successful";
}
else
{
item.ValidationResult = "Error: ";
}
}
return View(so.ToList());
You are now performing a database call per item in your list. This is really hard on your database and thus your performance. Try to itterate trough your excel result, gather all users and select them in one query. Make a list from this query result (else the query call is performed every time you access the list). Then perform a match between the result list and your excel.
You need to do something like this :
var ids = so.Select(i=>i.PersonId).Distinct().ToList();
// Hitting Database just for this time to get all Users Ids
var usersIds = db.Entity.Where(u=>ids.Contains(u.ID)).Select(u=>u.ID).ToList();
foreach (var item in so)
{
if (usersIds.Contains(item.PersonId))
{
item.ValidationResult = "Successful";
}
else
{
item.ValidationResult = "Error: ";
}
}
return View(so.ToList());

How to update records from an IList in a Foreach loop?

My controller is passing through a list which I then need to loop through and update every record in the list in my database. I'm using ASP.NET MVC with a repository pattern using Linq to Sql. The code below is my save method which needs to add a record to an invoice table and then update the applicable jobs in the job table from the db.
public void SaveInvoice(Invoice invoice, IList<InvoiceJob> invoiceJobs)
{
invoiceTable.InsertOnSubmit(invoice);
invoiceTable.Context.SubmitChanges();
foreach (InvoiceJob j in invoiceJobs)
{
var jobUpdate = invoiceJobTable.Where(x => x.JobID == j.JobID).Single();
jobUpdate.InvoiceRef = invoice.InvoiceID.ToString();
invoiceJobTable.GetOriginalEntityState(jobUpdate);
invoiceJobTable.Context.Refresh(RefreshMode.KeepCurrentValues, jobUpdate);
invoiceJobTable.Context.SubmitChanges();
}
}
**I've stripped the code down to just the problem area.
This code doesn't work and no job records are updated, but the invoice table is updated fine. No errors are thrown and the invoiceJobs IList is definitely not null. If I change the code by removing the foreach loop and manually specifying which JobId to update, it works fine. The below works:
public void SaveInvoice(Invoice invoice, IList<InvoiceJob> invoiceJobs)
{
invoiceTable.InsertOnSubmit(invoice);
invoiceTable.Context.SubmitChanges();
var jobUpdate = invoiceJobTable.Where(x => x.JobID == 10000).Single();
jobUpdate.InvoiceRef = invoice.InvoiceID.ToString();
invoiceJobTable.GetOriginalEntityState(jobUpdate);
invoiceJobTable.Context.Refresh(RefreshMode.KeepCurrentValues, jobUpdate);
invoiceJobTable.Context.SubmitChanges();
}
I just can't get the foreach loop to work at all. Does anyone have any idea what I'm doing wrong here?
It seems like the mostly likely cause of this problem is that the invokeJobs collection is an empty collection. That is it has no elements hence the foreach loop effectively does nothing.
You can verify this by adding the following to the top of the method (just for debugging purposes)
if (invoiceJobs.Count == 0) {
throw new ArgumentException("It's an empty list");
}
Change this
var jobUpdate = invoiceJobTable.Where(x => x.JobID == 10000).Single();
jobUpdate.InvoiceRef = invoice.InvoiceID.ToString();
invoiceJobTable.GetOriginalEntityState(jobUpdate);
invoiceJobTable.Context.Refresh(RefreshMode.KeepCurrentValues, jobUpdate);
invoiceJobTable.Context.SubmitChanges();
to
var jobUpdate = invoiceJobTable.Where(x => x.JobID == 10000).Single();
jobUpdate.InvoiceRef = invoice.InvoiceID.ToString();
invoiceJobTable.SubmitChanges();
It looks like your GetOriginalEntityState doesn't actually do anything, because you don't use the returned value. I can't see any reason why you are making the DataContext.Refresh() call. All it does is erase the changes you made, thus making your "foreach loop not work"

Categories

Resources