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.
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();
I have a workflow table that takes all the steps of a process. Lets work with 2 of those statuses:
Saved (new item saved but not submitted yet)
Submitted (item submitted for review)
Now I want to create a BatchSumbit function that will submit all the unsubmitted items. For this I need to query for all the items which has a latest workflow status of "Saved". All the historical workflow entries for the item still exist and it can go from "Submitted" back to "Saved" a few times.
Here is the table structure:
Now i want a linq query that will give me what I require:
from wasteInformation in wasteDB.WasteInformations
join workFlowHistory in wasteDB.WorkFlowHistories on wasteInformation.WasteInformationId equals workFlowHistory.WasteInformationId
// Join with last instance in workflow table (where workflowHistory.DateAdded is greatest)
where workFlowHistory.WorkFlowStep == "Saved"
&& wasteInformation.WasteProgrammeId == captureModel.WasteProgrammeId
&& wasteInformation.WasteSourceId == captureModel.WasteSourceId
select new
{
WasteInformationId = wasteInformation.WasteInformationId,
FinancialQuarter = wasteInformation.FinancialQuarter,
FinancialYear = wasteInformation.FinancialYear,
WasteProgrammeId = wasteInformation.WasteProgrammeId,
WasteMonth = wasteInformation.WasteMonth,
WasteYear = wasteInformation.WasteYear,
DateCaptured = wasteInformation.DateCaptured,
WasteSourceId = wasteInformation.WasteSourceId,
WasteDate = wasteInformation.WasteDate
}
The query as it is will give be all the saved entries for the item. I want it to give me the item if that item's last entry has a WorkFlowStep of "Saved"
Edit:
I've got something that looks like it works. Still need to test it some more:
var SavedWasteInformation = wasteDB.WasteInformations.Where(wi => wi.WorkFlowHistories.FirstOrDefault(wf => wf.DateAdded == wi.WorkFlowHistories.Max(wf_in => wf_in.DateAdded)).WorkFlowStep == "Saved"
&& wi.WasteProgrammeId == captureModel.WasteProgrammeId
&& wi.WasteSourceId == captureModel.WasteSourceId);
Edit:
My solution above and Vladimirs's below both seem to work, but after inspecting the execution plans Vladimirs's looks like the better option:
Providing that you have collection of WorkFlowHistories on your WasteInformation I believe that query will select WasteInformations with their latest WorkFlowHistory (if any):
from wasteInformation in wasteDB.WasteInformations
where wasteInformation.WasteProgrammeId == captureModel.WasteProgrammeId
&& wasteInformation.WasteSourceId == captureModel.WasteSourceId
select new
{
WasteInformation = wasteInformation,
LastSavedWorkFlowHistory = wasteInformation.WorkFlowHistories
.Where(x => x.WorkFlowStep == "Saved")
.OrderByDescending(x => x.DateAdded)
.FirstOrDefalt()
}
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();
I'm trying to optimize the below LINQ query to improve it's speed performance. The number of objects it's searching against could be in the tens of thousands.
var lQuery = from o in oEvents
where (o.oSalesEvent != null && o.oSalesEvent.OccurDate < oCalcMgr.OccurDate && (
(oCalcMgr.InclTransTypes == Definitions.TransactionTypes.SalesAll) ?
(o.oSalesEvent.EventStateID == ApprovedID || o.oSalesEvent.EventStateID == PendingID) :
o.oSalesEvent.EventStateID == ApprovedID)) &&
((oCalcMgr.InclTransTypes == Definitions.TransactionTypes.SalesAll) ?
(o.oSalesMan.oEmployment.EventStateID == ApprovedID || o.oSalesMan.oEmployment.EventStateID == PendingID) :
o.oSalesMan.oEmployment.EventStateID == ApprovedID)
select new { SaleAmount = o.SaleAmount.GetValueOrDefault(), CompanyID = o.oSalesEvent.CompanyID };
The query basically says, give me the sales amounts and company ids from all sale events that occurred prior to a certain date. The sale event's status and the salesman's employment status should either always be "approved" or they can be also "pending" if specified.
As you can see there's a date comparison and a couple of integer comparisons. Which integer comparison used is based on whether or not a property matches a certain Enum value.
I have some ideas of my own on ways to go about the optimization, but I want to hear others thoughts, who might have more insight into how LINQ would translate this query behind the scenes.
Thanks
It seems to me that your biggest challenge is that you're doing multiple criteria checks in your Linq statement that will take alot of time.
What about creating a new property in oEvents - Say "IsEligable" and set it's value within the Set statements of your other variables (much faster than constant re-querying of each variable in the Linq).
Then, by the time you get to this part of your code, you could update your Linq to be something along the lines of:
var lQuery = from o in oEvents
where (o.oSalesEvent != null && o.oSalesEvent.OccurDate < oCalcMgr.OccurDate && o.IsEligable == True)
select new { SaleAmount = o.SaleAmount.GetValueOrDefault(), CompanyID = o.oSalesEvent.CompanyID };
... I'm guessing that would speed up the execution, but just a thought...
This is as much to improve readability as to possibly speed it up, but give this a try:
var lQueryTemp = from o in oEvents
where (o.oSalesEvent != null && o.oSalesEvent.OccurDate < oCalcMgr.OccurDate)
if (oCalcMgr.InclTransTypes == Definitions.TransactionTypes.SalesAll)
{
lQueryTemp = from o in lQueryTemp
where (o.oSalesEvent.EventStateID == ApprovedID || o.oSalesEvent.EventStateID == PendingID) &&
(o.oSalesMan.oEmployment.EventStateID == ApprovedID || o.oSalesMan.oEmployment.EventStateID == PendingID);
}
else
{
lQueryTemp = from o in lQueryTemp
where (o.oSalesEvent.EventStateID == ApprovedID && o.oSalesMan.oEmployment.EventStateID == ApprovedID);
}
var lQuery = from o in lQueryTemp
select new { SaleAmount = o.SaleAmount.GetValueOrDefault(), CompanyID = o.oSalesEvent.CompanyID };
This might speed it up by pulling out both checks of oCalcMgr.InclTransTypes, which is effectively a constant for purposes of this query.