I am trying to condense my code by avoiding multiple foreach loops to accomplish this task. I have a listbox that is populated by Table A. I need to compare those values with Table B to populate another list.
Table A has a 1 to many relationship with Table B and while my solution worked for the time being, it is using quite a bit of memory so I need to condense it.
List<int> listProj = new List<int>();
var _tableB = from t in TableB
where t.StatID == 1 || t.StatID == 2
select p.ID;
var _tableA = from ListItem n in lstTableA.Items
where _tableB.Contains(int.Parse(n.Value)) && n.Selected == true
select n;
foreach (ListItem i in _tableA)
{
int affID = Convert.ToInt32(i.Value);
if (TableB.Where(t => t.ID == affID && t.StatID == 1 || t.StatID == 2).Any()
{
foreach(var item in TableB.Where(t => t.ID == affID && t.StatID == 1 || t.StatID == 2)
{
int pID = Convert.ToInt32(item.pID);
listProject.Add(projID);
}
}
}
The main problem is that these two loops are looping through quite a bit of records which is causing a memory leak. I feel that there is a way to grab many records at once and add them to the list, hence the one to many relationship between Table A and Table B.
I think this would give you the same result as the whole code above unless I'm making a mistake on the logic of your program.
This would return the project ids:
List<int> listProj = (from t in TableB
where (from n in lstTableA.Items.Cast<ListItem>().ToList()
where n.Selected == true
select n).Any(g => int.Parse(g.Value) == t.ID)
&& (t.StatID == 1 || t.StatID == 2)
select t.pID).ToList();
Related
DELETE From Table
WHERE ID in (1,2,3, ... )
Is there any way to produce following query in LINQ? I tried RemoveRange, but from SQL Server Profiler find that it actually deletes records separately
You could first define the item(s) to remove, then iterate over the list removing them one by one: (note that the whole operation has to be done inside database context scope otherwise it won't work)
var toRemove = list.Where(l => l.id == 1 || l.id == 2 || l.id == 3);
foreach (var item in toRemove)
{
databasecontext.table.Remove(item); //replace databasecontext.table with your own context and table name
}
You can write it in single line
table.RemoveAll(tbl => tbl.id == 1 || tbl.id == 2 || tbl.id == 3);
Hope this helps.
Try this piece of code to make this, It will work for you.
DataContextClass _DbContext = new DataContextClass();
var remove = _DbContext.tableName.where(x=>x.id >= 1 && x.id <= endValue);
if(remove != null)
{
db.logins.RemoveRange(remove);
db.SaveChanges();
}
I have this scenario in which i query with FindByMany (which takes the lambda and returns post if user country and category matches, (as seen in the "else")
But now i need to customize the return with prefered subcategories from users, so what im doing is query n times foreach subcategory and just addRange. I dont want to query 5 times the db if the user has 5 subcategories as favorite, but i dont know how to apply a dinamic OR.
So my question is, how can this code be improved for performance.
var posts = new List<Content>();
if (request.UserId != 0)
{
var user = _userRepository.FindBy(u => u.Id == request.UserId);
if (user != null && user.SubCategories.Any())
{
foreach (var temp in user.SubCategories.Select(subCategory => _contentRepository.FindManyBy(
c =>
c.Country.Id == country.Id && c.Category.Id == theCategory.Id &&
c.SubCategory.Id == subCategory.Id).ToList()))
{
posts.AddRange(temp);
}
}
}
else
{
posts = _contentRepository.FindManyBy(
c => c.Country.Id == country.Id && c.Category.Id == theCategory.Id
).ToList();
}
Could you not just materalise the sub-categories into a list, and then in your FindBy use a thatlist.Contains()?
You can get the user's sub-categories with one query and then use the list and the Contains method to filter the relevant posts. Contains method is supported by most LINQ query provides and should be translated into a single database query.
var subcategories = user.SubCategories.ToList();
foreach (var temp in _contentRepository.FindManyBy(
c =>
c.Country.Id == country.Id && c.Category.Id == theCategory.Id &&
subcategories.Contains( subCategory.Id ) ).ToList()))
{
posts.AddRange(temp);
}
You can build expression for where clause using Expression.OrElse or use enter link description here
The core of the problem is that you're forcing query execution for each item instead of dynamically building the query. #Milney has the right idea; example code below.
IEnumerable<int> subCategoryIds = user.SubCategories.Select(x => x.Id);
var posts = _contentRepository.FindByMany(c => c.Country.Id == country.Id
&& c.Category.Id == theCategory.Id
&& subCategoryIds.Contains(c.SubCategoryId)).ToList();
As my code is taking long time to process. I analyzed the code & searched the part of the code which is taking lots of time.
In my listTempInOut there are over 100000 records. SDetails also have more records. I wanted to update 2 fields in the model. So following is the code :-
var dataUpd = (from A in tempSS
from B in SDetails
from C in listTempInOut
where A.Id == B.Id
&& A.Shift == B.Shift && A.Employee == C.Employee && A.SDate == C.Time_Date1
select new { A.SId, B.Status, C }).ToList();
foreach (var row in dataUpd)
{
row.C.Time_Field1 = row.ShiftId;
row.C.Time_Field2 = row.Status.ToString();
}
What change can i do in the above code to improve the performance so that it takes less time to execute the code.
Updates in the entity framework can be very slow, try setting the AutoDetectChangesEnabled property to false in your context (see code below, I'm not sure what your context is actually called so I called it "myContext"). You must remember to set it back to true when you are done with your updates so I'd recommend wrapping your code in a try/finally block.
try
{
myContext.Configuration.AutoDetectChangesEnabled = false;
var dataUpd = (from A in tempSS
from B in SDetails
from C in listTempInOut
where A.Id == B.Id
&& A.Shift == B.Shift && A.Employee == C.Employee && A.SDate == C.Time_Date1
select new { A.SId, B.Status, C }).ToList();
foreach (var row in dataUpd)
{
row.C.Time_Field1 = row.ShiftId;
row.C.Time_Field2 = row.Status.ToString();
}
}
finally
{
myContext.Configuration.AutoDetectChangesEnabled = true;
}
I added data to an ObservableCollection from a LINQ query:
foreach (var item in test4)
{
lstPareto.Add(new clsPareto(Convert.ToInt32(item.Step), Convert.ToInt32(item.LogID), test3.Where(p => p.Step.Equals(item.Step) && p.LogID.Equals(item.LogID)).Count()));
}
And this works fine. I get the items I want and convert them to an int when adding them to the list.
Then I have the following queries that pulls data from multiple databases:
int intCmbTestNr = Convert.ToInt32(m_strCmbTestNrSelectedItem);
var productIndex = (from x in m_dcSQL_ConnectionProdTest.DC3_VersionReleases
where x.TestNumber.Equals(intCmbTestNr)
select x.ProductIndex).First();
var version = ((from y in m_dcSQL_ConnectionProdTest.DC3_MainSetups
where y.ProductIndex == productIndex && y.SubVersion == 0
select y.Version).Max());
var versionIndex = (from z in m_dcSQL_ConnectionProdTest.DC3_MainSetups
where z.ProductIndex == productIndex && z.Version.Equals(version) && z.SubVersion == 0
select z.VersionIndex).First();
var subFuncName = from a in m_dcSQL_ConnectionProdTest.DC3_SubFunctions
where a.VersionIndex == versionIndex && a.FunctionNumber == lstPareto.Select(b => b.intStep) && a.SubFunctionNumber == lstPareto.Select(c => c.intStep)
select a.SubFunctionName;
Consider subFuncName. What I am trying to achieve here is to compare a.FunctionNumber to intStep and a.SubFunctionNumber to intLogID of the list lstPareto. However, it says the following: "Operator '==' cannot be applied to operands of type'int' and 'System.Collections.Generic.IEnumerable". I think I know the reason for this, seeing as I'm trying to compare a single int to a whole collection. But how do I compare to every single item intStep and intLogID of the list? I cannot seem to wrap my head around this. Do I use a foreach loop somewhere? Can somebody get me back on track?
Sorry if the title is somewhat vague, couldn't really think of a good one.
If both FunctionNumber and SubFunctionNumber is int:s. Then you can change the condition to this:
lstPareto.Select(b => b.intStep).Contains(a.FunctionNumber)
&& lstPareto.Select(c => c.intStep).Contains(a.SubFunctionNumber)
Update
The reason is most probably because you do not have .ToList(), .First(), .Single() in the query. Depends a little bit what you expect. You could change it to this:
var subFuncName = (from a in m_dcSQL_ConnectionProdTest.DC3_SubFunctions
where a.VersionIndex == versionIndex && lstPareto.Select(b => b.intStep).Contains(a.FunctionNumber)
&& lstPareto.Select(c => c.intStep).Contains(a.SubFunctionNumber)
select a.SubFunctionName).ToList();
Reference:
Enumerable.Contains Method
Considere this piece of code in LINQ (please focus on var list2):
var list1 = ....... /* This linq doesnt matter. Just for clarify that it is used in the below linq */
var list2 = dba.OrderForm
.Where(q => q.OrderPriority.OrderPriorityID == orderpriorityID
&& q.StockClass.StockClassID == stockclassID
&& dba.AuditTrailLog.Where(log => q.OrderID == log.ObjectID)
.Any(log => log.ColumnInfoID == 486
&& log.OldValue == "2"
&& log.NewValue == "3")
&& dba.AuditTrailLog.Where(log2 => q.OrderID == log2.ObjectID)
.Any(log2 => log2.ColumnInfoID == 487
&& log2.OldValue == "1"
&& log2.NewValue == "2")
&& lista.Contains(q.OrderID));
This way I have in list2 a list of records that belongs to OrderForm model. I need to pass it to another model called ViewResult:
What I need is to get the variable log2.ModificationDate that belongs to AuditTrailLog table but it is not included on OrderForm Model
List<ViewResult> vr = new List<ViewResult>();
foreach (OrderForm o in list2)
{
ViewResult r = new ViewResult();
r.NumOrden = o.FormNo;
r.Title = o.Title;
r.Com = o.OrderPriority.Descr;
r.OClass = o.StockClass.Descr;
r.RodT = /* <<------ Here is where I need to assign log2.ModificationDate
vr.Add(r);
}
Thanks.
What I understand is AuditTrailLog relation is null while you are getting data. And you want to fill it with related data.
You must Include this table like:
(That means you are doing join on sql)
var list2 = dba.OrderForm.Include("AuditTrailLog")...
It is important the relation between them. "One to many" or "many to one". Use AuditTrailLog or AuditTrailLogs according to your relation.