I have already found this T-SQL query (and it works) for returning the whole sub-tree from specified node:
SELECT node.id
FROM cuenta AS node,
cuenta AS parent,
cuenta AS sub_parent,
(
SELECT node.id, (COUNT(parent.id) - 1) AS depth
FROM cuenta AS node,
cuenta AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.id = 16
GROUP BY node.id
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.id = sub_tree.id
GROUP BY node.id
How Can I code this in c# linq query?
I already tried with this, but it doesn't work:
var nodeList = (from node in db.GetAll<Cuenta>()
from parent in db.GetAll<Cuenta>()
from sub_parent in db.GetAll<Cuenta>()
from sub_tree in (
from node2 in db.GetAll<Cuenta>()
from parent2 in db.GetAll<Cuenta>()
where node2.Lft >= parent2.Lft && node2.Lft <= parent2.Rgt && node2.Id == nodeId
group node2 by node2.Id into g
//orderby node2.Lft
select new { Id = g.Key, Depth = g.Count() - 1 })
where
node.Lft >= parent.Lft && node.Lft <= parent.Rgt &&
node.Lft >= sub_parent.Lft && node.Lft <= sub_parent.Rgt &&
sub_parent.Id == sub_tree.Id
group node by node.Id into g2
//orderby node.Lft
//select new { Id = g.Key, Depth = g2.Count() - sub_tree.Depth + 1 });
select new { Id = g2.Key }).ToList();
Thanks!
I solved it:
var nodeList = (from node in db.GetTable<Cuenta>()
from parent in db.GetTable<Cuenta>()
from sub_parent in db.GetTable<Cuenta>()
from sub_tree in (
from node in db.GetTable<Cuenta>()
from parent in db.GetTable<Cuenta>()
where node.Lft >= parent.Lft && node.Lft <= parent.Rgt && node.Id == nodeId
group node by node.Id into g
select new { Id = g.Key, Depth = g.Count() - 1 })
where
node.Lft >= parent.Lft && node.Lft <= parent.Rgt &&
node.Lft >= sub_parent.Lft && node.Lft <= sub_parent.Rgt &&
sub_parent.Id == sub_tree.Id
group node by node.Id into g
select new { Id = g.Key }).ToList();
Related
I have this table
EquipmentId Value Date
1 2 11/04/2013
1 1 11/04/2013
2 3 11/04/2013
2 2 10/04/2013
2 5 10/04/2013
3 1 10/04/2013
3 3 11/04/2013
I want to group these items by date, and have a dictionary with the date as a key and the sum of the maxs of the all equipments values in that day
the result would be like this
[10/04/2013: 6] // 6 = 5 (as the max of values of the the equipmetId 2) + 1 (as the max of values of the the equipmetId 3)
[11/04/2013: 5] // 5 = 2(as the max of values of the the equipmetId 1) + 3(as the max of values of the the equipmetId 3)
I managed to make the query to get this without the sum, meaning for only one equipment.
var consumptionValues = (from c in context.ConsumptionSet
join pi in context.PropertiesInstanceSet on c.PropertiesInstanceID equals pi.PropertiesInstanceID
join ep in context.EquipmentPropertiesSet on pi.EquipmentPropertiesID equals ep.EquipmentPropertiesID
join e in context.EquipmentSet on ep.EquipmentID equals e.EquipmentID
where (e.EquipmentID == equipmentId && pi.ProprietesName == ProprietesName.Energy && c.Date <= DateTime.Now && c.Date >= firstDayDate)
group c by SqlFunctions.DatePart("weekday", c.Date) into grp
select new
{
dayOfWeek = (DayOfWeek)grp.Key.Value - 1,
value = grp.Max(c => c.Value),
}).ToDictionary(c => c.dayOfWeek.ToString(), c => c.value);
It's the complete query with all the joins, in the example I just gave a simplified example.
Is it possible to do this in one single query ?
I have to say I'm not sure it will work, but you should give it a shot:
var consumptionValues = (from c in context.ConsumptionSet
join pi in context.PropertiesInstanceSet on c.PropertiesInstanceID equals pi.PropertiesInstanceID
join ep in context.EquipmentPropertiesSet on pi.EquipmentPropertiesID equals ep.EquipmentPropertiesID
join e in context.EquipmentSet on ep.EquipmentID equals e.EquipmentID
where (e.EquipmentID == equipmentId && pi.ProprietesName == ProprietesName.Energy && c.Date <= DateTime.Now && c.Date >= firstDayDate)
group new { c, e } by SqlFunctions.DatePart("weekday", c.Date) into grp
select new
{
dayOfWeek = (DayOfWeek)grp.Key.Value - 1,
value = grp.GroupBy(i => i.e.EquipmentID).Sum(g => g.Max(i => i.c.Value)),
}).ToDictionary(c => c.dayOfWeek.ToString(), c => c.value);
So I have this function:
public static BaseList GetVersesByChapterVerseRanges(string translation, BaseList criteriaList)
{
BaseList returnValue = new BaseList();;
if(criteriaList.Count() > 0)
{
List<VerseMaster.BusinessLayer.Vers> queryList = new List<Vers>();
int bookId = criteriaList[0].Book.BookId;
int StartChapter = criteriaList[0].StartChapter;
int EndChapter = criteriaList[0].EndChapter;
int StartVerse = criteriaList[0].StartChapterStartVerse;
int EndVerse = criteriaList[0].EndChapterEndVerse;
var searchQuery = (from v in VerseMaster.BusinessLayer.Controller.Controller.VerseMasterEntities.Verses where v.Translation.ToLower().StartsWith(translation.ToLower()) && v.BookId == bookId && v.ChapterNumber >= StartChapter && v.ChapterNumber <= EndChapter && (v.ChapterNumber == StartChapter ? (v.VerseNumber >= StartVerse) : true) && (v.ChapterNumber == EndChapter ? (v.VerseNumber <= EndVerse) : true) orderby v.ChapterNumber, v.VerseNumber ascending select v);
for(int i = 1; i < criteriaList.Count(); i++)
{
bookId = criteriaList[i].Book.BookId;
StartChapter = criteriaList[i].StartChapter;
EndChapter = criteriaList[i].EndChapter;
StartVerse = criteriaList[i].StartChapterStartVerse;
EndVerse = criteriaList[i].EndChapterEndVerse;
VerseMaster.BusinessLayer.DataObjects.Helper.VerseSearchCriteria criteria = criteriaList[i];
searchQuery = (System.Linq.IOrderedQueryable<VerseMaster.BusinessLayer.Vers>)searchQuery.Concat(from v in VerseMaster.BusinessLayer.Controller.Controller.VerseMasterEntities.Verses where v.Translation.ToLower().StartsWith(translation.ToLower()) && v.BookId == bookId && v.ChapterNumber >= StartChapter && v.ChapterNumber <= EndChapter && (v.ChapterNumber == StartChapter ? (v.VerseNumber >= StartVerse) : true) && (v.ChapterNumber == EndChapter ? (v.VerseNumber <= EndVerse) : true) orderby v.ChapterNumber, v.VerseNumber ascending select v);
}
string traceString = ((System.Data.Objects.ObjectQuery)searchQuery).ToTraceString();
foreach (var entVerse in searchQuery)
{
VerseMaster.BusinessLayer.DataObjects.IVerse verse = new VerseMaster.BusinessLayer.DataObjects.Verse();
LoadVerseFromEntityVerse(ref verse, entVerse);
Console.Write(String.Format("Chapter={0} Verse={1} Text={2}\n", entVerse.ChapterNumber, entVerse.VerseNumber, entVerse.Verse));
//returnValue.Add((VerseMaster.BusinessLayer.DataObjects.Verse)verse);
}
}
return returnValue;
}
So for some reason I had to convert each of the parameters that go into the linq query into standard ints because of an error, not sure if its related. So the generated sql is:
SELECT
[UnionAll2].[C1] AS [C1],
[UnionAll2].[C2] AS [C2],
[UnionAll2].[C3] AS [C3],
[UnionAll2].[C4] AS [C4],
[UnionAll2].[C5] AS [C5],
[UnionAll2].[C6] AS [C6]
FROM (SELECT
[UnionAll1].[VerseId] AS [C1],
[UnionAll1].[ChapterNumber] AS [C2],
[UnionAll1].[VerseNumber] AS [C3],
[UnionAll1].[Verse] AS [C4],
[UnionAll1].[Translation] AS [C5],
[UnionAll1].[BookId] AS [C6]
FROM (SELECT
[Extent1].[VerseId] AS [VerseId],
[Extent1].[ChapterNumber] AS [ChapterNumber],
[Extent1].[VerseNumber] AS [VerseNumber],
[Extent1].[Verse] AS [Verse],
[Extent1].[Translation] AS [Translation],
[Extent1].[BookId] AS [BookId]
FROM [dbo].[Verses] AS [Extent1]
WHERE (( CAST(CHARINDEX(LOWER(#p__linq__0), LOWER([Extent1].[Translation])) AS int)) = 1) AND ([Extent1].[BookId] = #p__linq__1) AND ([Extent1].[ChapterNumber] >= #p__linq__2) AND ([Extent1].[ChapterNumber] <= #p__linq__3) AND ((CASE WHEN ([Extent1].[ChapterNumber] = #p__linq__4) THEN CASE WHEN ([Extent1].[VerseNumber] >= #p__linq__5) THEN cast(1 as bit) WHEN ( NOT ([Extent1].[VerseNumber] >= #p__linq__5)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1) AND ((CASE WHEN ([Extent1].[ChapterNumber] = #p__linq__6) THEN CASE WHEN ([Extent1].[VerseNumber] <= #p__linq__7) THEN cast(1 as bit) WHEN ( NOT ([Extent1].[VerseNumber] <= #p__linq__7)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1)
UNION ALL
SELECT
[Extent2].[VerseId] AS [VerseId],
[Extent2].[ChapterNumber] AS [ChapterNumber],
[Extent2].[VerseNumber] AS [VerseNumber],
[Extent2].[Verse] AS [Verse],
[Extent2].[Translation] AS [Translation],
[Extent2].[BookId] AS [BookId]
FROM [dbo].[Verses] AS [Extent2]
WHERE (( CAST(CHARINDEX(LOWER(#p__linq__8), LOWER([Extent2].[Translation])) AS int)) = 1) AND ([Extent2].[BookId] = #p__linq__9) AND ([Extent2].[ChapterNumber] >= #p__linq__10) AND ([Extent2].[ChapterNumber] <= #p__linq__11) AND ((CASE WHEN ([Extent2].[ChapterNumber] = #p__linq__12) THEN CASE WHEN ([Extent2].[VerseNumber] >= #p__linq__13) THEN cast(1 as bit) WHEN ( NOT ([Extent2].[VerseNumber] >= #p__linq__13)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1) AND ((CASE WHEN ([Extent2].[ChapterNumber] = #p__linq__14) THEN CASE WHEN ([Extent2].[VerseNumber] <= #p__linq__15) THEN cast(1 as bit) WHEN ( NOT ([Extent2].[VerseNumber] <= #p__linq__15)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1)) AS [UnionAll1]
UNION ALL
SELECT
[Extent3].[VerseId] AS [VerseId],
[Extent3].[ChapterNumber] AS [ChapterNumber],
[Extent3].[VerseNumber] AS [VerseNumber],
[Extent3].[Verse] AS [Verse],
[Extent3].[Translation] AS [Translation],
[Extent3].[BookId] AS [BookId]
FROM [dbo].[Verses] AS [Extent3]
WHERE (( CAST(CHARINDEX(LOWER(#p__linq__16), LOWER([Extent3].[Translation])) AS int)) = 1) AND ([Extent3].[BookId] = #p__linq__17) AND ([Extent3].[ChapterNumber] >= #p__linq__18) AND ([Extent3].[ChapterNumber] <= #p__linq__19) AND ((CASE WHEN ([Extent3].[ChapterNumber] = #p__linq__20) THEN CASE WHEN ([Extent3].[VerseNumber] >= #p__linq__21) THEN cast(1 as bit) WHEN ( NOT ([Extent3].[VerseNumber] >= #p__linq__21)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1) AND ((CASE WHEN ([Extent3].[ChapterNumber] = #p__linq__22) THEN CASE WHEN ([Extent3].[VerseNumber] <= #p__linq__23) THEN cast(1 as bit) WHEN ( NOT ([Extent3].[VerseNumber] <= #p__linq__23)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1)) AS [UnionAll2]
So the problem is that for some reason its treating each of the parameters I give it as if I sent 3 sets of the same parameter and concatenated so its returning the same set of verses 3 times. I'm not sure why its doing this as I am not an expert of linq or the entity framework, any suggestions?
This is a very tricky example of the modified closure issue. In the for loop you generate a query part that uses the variables bookId etc. At the time that your query is executed it uses the values that these variables have at that moment, which are the values after the last iteration of the loop. (The tricky part is that usually the loop variable is captured, but here it is about variables that were declared outside the loop scope).
It would be different if you declared the variables within the for loop, because each query part would capture its own instance of the variable (which is called a closure).
The good news: you can do this and at the same time clean up your code!
if(criteriaList.Count() > 0)
{
IQueryable<Verse> baseQuery = null;
for(int i = 0; i < criteriaList.Count(); i++) // starting i = 0 now !
{
int bookId = criteriaList[0].Book.BookId;
int StartChapter = criteriaList[0].StartChapter;
int EndChapter = criteriaList[0].EndChapter;
int StartVerse = criteriaList[0].StartChapterStartVerse;
int EndVerse = criteriaList[0].EndChapterEndVerse;
searchQuery = (IOrderedQueryable<Vers>)searchQuery.Concat(
from v in Controller.Controller.VerseMasterEntities.Verses
where v.Translation.ToLower().StartsWith(translation.ToLower())
&& v.BookId == bookId
&& v.ChapterNumber >= StartChapter
&& v.ChapterNumber <= EndChapter
&& (v.ChapterNumber == StartChapter ? (v.VerseNumber >= StartVerse) : true)
&& (v.ChapterNumber == EndChapter ? (v.VerseNumber <= EndVerse) : true)
select v);
if (i == 0)
baseQuery = searchQuery;
else
baseQuery = baseQuery.Concat(searchQuery);
}
...
(do the ordering later)
In the below code I expect to retrn n rows but it always returns zero rows as my initial set has zero records. Ideally it should be doing a UNION ALL and returning me records for all of the integers in the integer list clearanceTotals{6,7,8,9,17}
Any idea how to go about it?
var tbl = (from a in db.Applicants
where a.Id == null
select new { a.Id, a.Firstname, a.Lastname });
int thisTag;
foreach (int c in clearanceTotals)
{
switch (c)
{
case 6:
thisTag = 38;
break;
case 8:
thisTag = 39;
break;
case 17:
thisTag = 39;
break;
case 7:
thisTag = 42;
break;
case 9:
thisTag = 44;
break;
}
tbl = (from a in db.Applicants
join ad in db.ApplicantDeployments on a.Id equals ad.ApplicantId
join aa in db.ApplicantAttachments on a.Id equals aa.ApplicantId
where a.Nationality == 15 && a.DoNotUse == false && a.ClearanceStatus == c
&& aa.Tag == thisTag
select new { a.Id, a.Firstname, a.Lastname }).Union(tbl);
}
I think the problem is that you're capturing the loop variable (c) in the query, so when the query is executed, it uses only the latest value of c. Try copying c to a variable inside the loop:
foreach (int c in clearanceTotals)
{
int c2 = c;
...
...
where a.Nationality == 15 && a.DoNotUse == false && a.ClearanceStatus == c2
...
OK so i got this to work but its additional code plus additional variables
var temp = (from a in db.Applicants
where a.Id == null
select a.Id).ToList();
int thisTag;
foreach (int c in clearanceTotals)
{
switch (c)
{
case 6:
thisTag = 38;
break;
case 8:
thisTag = 39;
break;
case 17:
thisTag = 39;
break;
case 7:
thisTag = 42;
break;
case 9:
thisTag = 44;
break;
}
temp = temp.Union(from a in db.Applicants
join ad in db.ApplicantDeployments on a.Id equals ad.ApplicantId
join aa in db.ApplicantAttachments on a.Id equals aa.ApplicantId
where a.Nationality == 15 && a.DoNotUse == false && a.ClearanceStatus == c
&& aa.Tag == thisTag
select a.Id).ToList();
}
var tbl = (from a in db.Applicants
join ad in db.ApplicantDeployments on a.Id equals ad.ApplicantId
where temp.Contains(a.Id)
select new { a.Id, a.Firstname, a.Lastname }).Distinct();
I have a little problem.
i should implement a logic for a treeList which consist from a single parent and more children grouped into more groups by ID's.
I have an action which treats all nodes:
long callerGroup = -1L;
if (callerNode != null)
{
var service = this.tlServices.GetDataRecordByNode(callerNode) as __ServiceInfo;
if (service != null)
{
callerGroup = service.Group;
}
}
Action<TreeListNodes> action = null;
action = (nodes) =>
{
if (nodes != null && nodes.Count > 0)
{
foreach (TreeListNode node in nodes)
{
if (node.Level == 0 && !node.Checked)
{
node.Checked = true;
break;
}
else
{
var service = this.tlServices.GetDataRecordByNode(node) as __ServiceInfo;
if (service != null)
{
var group = service.Group;
//for ' 1 <= group <= 100' -> Mandatory Service, only ONE from group
if (callerGroup >= 1 && callerGroup <= 100)
{
if (group >= 1 && group <= 100)
{
//node.Checked = true; - not done
}
}
//for ' 101 <= group <= 1000 ' -> Mandatory Service, minimum ONE from group, but allow and MORE
if (callerGroup >= 101 && callerGroup <= 1000)
{
}
//for ' group >= 1001 ' -> optional Service, ALL from group
if (callerGroup >= 1001 && group >= 1001)
{
node.Checked = !node.Checked; // --> DONE.
}
}
}
action(node.Nodes);
}
}
};
action(this.tlServices.Nodes);
I have 3 cases:
#1. if 1 <= group <= 100 -> Mandatory Service, allow only ONE from group
#2. if 101 <= group <= 1000 -> Mandatory Service, allow minimum ONE from group, but allow and MORE
#3. if group >= 1001 -> optional Service, Check/ Uncheck ALL from group.
Result:
The #3 I've done easy, but how can i implement #1.
for #1 i found an implementation:
//for ' 1 <= group <= 100' -> Mandatory Service, only ONE from group
if (callerGroup >= 1 && callerGroup <= 100)
{
if (group >= 1 && group <= 100)
{
foreach (TreeListNode nd in nodes)
{
var svc = this.tlServices.GetDataRecordByNode(nd) as __ServiceInfo;
long gr = svc.Group;
if (gr == callerGroup && nd.Checked == true)
{
nd.Checked = false;
}
}
}
}`
This is fine, it produces a left join
var q =
from c in categories
join p in products
on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };
But what about if I wanted to do something like this:
...
on p.date between c.startdate and c.enddate
...
var q =
from c in categories
join p in products
on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
where p.date >= c.startdate && p.date <= c.enddate
select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };