how to order with parentID and ordermenu - c#

i have menu table with Following characteristics:
tblMenu: ID, Title, ParentID, OrderM
i want select menu and order with ParentID and OrderM as follows:
EX:
data in table:
ID = 1 Title = menu1 ParentID = 0 OrderM = 1
ID = 2 Title = menu2 ParentID = 0 OrderM = 2
ID = 3 Title = menu3 ParentID = 0 OrderM = 3
ID = 4 Title = submenu2-1 ParentID = 2 OrderM = 1
ID = 5 Title = submenu2-2 ParentID = 2 OrderM = 2
ID = 6 Title = submenu1-2 ParentID = 1 OrderM = 2
ID = 7 Title = submenu1-1 ParentID = 1 OrderM = 1
I want the following result with select LINQ:
menu1
submenu1-1
submenu1-2
menu2
submenu2-1
submenu2-2
menu3

This should work (Sample):
var result =
l.Where(c => c.ParentID == 0)
.Select(c => new {Menu = c, Sub = l.Where(ci => ci.ParentID == c.ID).OrderBy(s => s.OrderM)})
.OrderBy(ao => ao.Menu.OrderM)
.SelectMany(ao => ao.Sub.Count() == 0 ? new List<C> {ao.Menu} : new List<C> {ao.Menu}.Concat(ao.Sub));

If it's the ordering that you're having trouble with, try using OrderBy and ThenBy to achieve the order that you require.
For example:
var items = source.OrderBy(i => i.OrderM).ThenBy(o => o.ParentID);

Related

Calculate 2 table where condition - Linq

i have 2 table ,
produk table
id produk batch qty
1 AAA ADADAD 2
2 BBB ADADAD 2
3 BBB AAAAAA 2
...............
and move table,
id produk batch qty
1 BBB ADADAD 1
and i want showing table after qty from stok table minus qty from move table, what i want table
PRODUK BATCH QTY
AAA ADADAD 2
BBB ADADAD 1
BBB AAAAAA 2
and this my query
var obj = _db.produk
.Groupby(a=> new {a.code,a.batch})
.Select(a=> new {
produk = a.key.code,
batch = a.Key.batch,
qty = _db.move.Where(c => a.Any(p => p.code == a.code && p.batch == a.batch)).Sum(a=>a.qty)
}).tolist();
but not working
You have to do LEFT JOIN to grouped move table.
var moves =
from m in _db.move
group m by { m.code, m.batch } into g
select
{
g.Key.code,
g.Key.batch,
qty = g.Sum(x => x.qty)
};
var query =
from p in _db.produk
join m in moves on new { p.code, p.batch } equals { m.code, m.batch } into j
from m in j.DefaultIfEmpty()
select new
{
produk = p.code,
batch = p.batch.
qty = p.qty - (int?)m.qty ?? 0
};
If you prefer method syntax over query syntax then you can write your query as this:
var availableItems = repository
.GroupJoin(purchases,
stock => new { stock.Product, stock.Batch },
move => new { move.Product, move.Batch },
(stock, moves) => new { Stock = stock, Moves = moves })
.SelectMany(
stockAndRelatedMoves => stockAndRelatedMoves.Moves.DefaultIfEmpty(),
(stockAndRelatedMoves, relatedMove) => new
{
stockAndRelatedMoves.Stock.Product,
stockAndRelatedMoves.Stock.Batch,
Quantity = stockAndRelatedMoves.Stock.Quantity - (relatedMove?.Quantity ?? 0)
})
.ToList();
As you can see instead of GroupBy you need to use GroupJoin and instead of simple Select you need SelectMany to retrieve items from the joined records.
Some explanation:
stock => new { stock.Product, stock.Batch }: Anonymous type is used here because multiple fields are used in the join
stockAndRelatedMoves => stockAndRelatedMoves.Moves.DefaultIfEmpty(): it is needed because of left outer join
(relatedMove?.Quantity ?? 0): relatedMove can be null that's why we substitute it with 0
In the above code I've used the following collections:
var repository = new List<Stock>
{
new Stock { Id = 1, Product = "AAA", Batch = "ADADAD", Quantity = 2 },
new Stock { Id = 2, Product = "BBB", Batch = "ADADAD", Quantity = 2 },
new Stock { Id = 3, Product = "BBB", Batch = "AAAAAA", Quantity = 2 },
};
var purchases = new List<Move>
{
new Move { Id = 1, Product = "BBB", Batch = "ADADAD", Quantity = 1 }
};
You could also query the produck table, then, in the Select statement, filter the move table based on the produck's batch and produck properties, then calculate the qty.
Code as below:
List<Produk> produks = new List<Produk>()
{
new Produk(){ id = 1, produk= "AAA", batch="ADADAD", qty = 2},
new Produk(){ id = 2, produk= "BBB", batch="ADADAD", qty = 2},
new Produk(){ id = 3, produk= "BBB", batch="AAAAAA", qty = 2},
};
List<Remove> removes = new List<Remove>()
{
new Remove(){ id=1, produk="BBB", batch="ADADAD", qty=1}
};
var result = (from p in produks
select new Produk
{
id = p.id,
produk = p.produk,
batch = p.batch,
qty = p.qty - removes.Where(c => c.produk == p.produk && c.batch == p.batch).Sum(c => c.qty)
}).ToList();
The result like this:

LINQ Join usage data from two data sets into one

What I have:
Two lists of the following model:
int SubscriptionId
int ItemId
double Usage
double EffectiveRate
string ResourceName
string UnitOfMeasure
The first contains usage data of the last month like this:
SubscriptionId ItemId Usage EffectiveRate ResourceName UnitOfMesaure
_________________________________________________________________________
1 1 2 2,75 R1 U1
1 2 3 1,50 R2 U2
The seconds contains usage data of the current month like this:
SubscriptionId ItemId Usage EffectiveRate ResourceName UnitOfMesaure
_________________________________________________________________________
1 1 5 2,75 R1 U1
1 3 2 1,50 R3 U3
What I want:
This should be merge in a list like this:
SubscriptionId ItemId UsageThis UsageLast EffRate ResName UOM
_________________________________________________________________________
1 1 5 2 2,75 R1 U1
1 2 0 3 1,50 R2 U2
1 3 2 0 1,50 R3 U3
What I have:
//data for both months available
if (resourcesThisMonth.Any() && resourcesLastMonth.Any())
{
//join both months
resources = from resourceLastMonth in resourcesLastMonth
join resourceThisMonth in resourcesThisMonth
on new { resourceLastMonth.SubscriptionId, resourceLastMonth.ItemId } equals new { resourceThisMonth.SubscriptionId, resourceThisMonth.ItemId }
select new Resource
{
SubscriptionId = resourceThisMonth.SubscriptionId,
ItemId = resourceThisMonth.ItemId,
UsageThisMonth = resourceThisMonth.Usage,
UsageLastMonth = resourceLastMonth.Usage,
EffectiveRate = resourceThisMonth.EffectiveRate,
ResourceName = resourceThisMonth.ResourceName,
UnitOfMeasure = resourceThisMonth.UnitOfMeasure
};
//resources only last month available
var resourcesOnlyLastMonth = resourcesLastMonth.Where(r => !resourcesThisMonth.Where(s => s.ItemId == r.ItemId && s.SubscriptionId == r.SubscriptionId).Any())
.Select(r => new Resource
{
SubscriptionId = r.SubscriptionId,
ItemId = r.ItemId,
UsageThisMonth = 0.0,
UsageLastMonth = r.Units,
EffectiveRate = r.EffectiveRate,
ResourceName = r.ResourceName,
UnitOfMeasure = r.UnitOfMeasure
});
//resources only this month available
var resourcesOnlyThisMonth = resourcesThisMonth.Where(r => !resourcesLastMonth.Where(s => s.ItemId == r.ItemId && s.SubscriptionId == r.SubscriptionId).Any())
.Select(r => new Resource
{
SubscriptionId = r.SubscriptionId,
ItemId = r.ItemId,
UsageThisMonth = r.Usage,
UsageLastMonth = 0.0,
EffectiveRate = r.EffectiveRate,
ResourceName = r.ResourceName,
UnitOfMeasure = r.UnitOfMeasure
});
//union data
resources = resources.Union(resourcesOnlyLastMonth);
resources = resources.Union(resourcesOnlyThisMonth);
}
//data for last month available
else if (resourcesLastMonth.Any())
{
resources = from resource in resourcesLastMonth
select new Resource
{
SubscriptionId = resource.SubscriptionId,
ItemId = resource.ItemId,
UsageThisMonth = 0.0,
UsageLastMonth = resource.Usage,
EffectiveRate = resource.EffectiveRate,
ResourceName = resource.ResourceName,
UnitOfMeasure = resource.UnitOfMeasure
};
}
//data for this month available
else if (resourcesThisMonth.Any())
{
resources = from resource in resourcesThisMonth
select new Resource
{
SubscriptionId = resource.SubscriptionId,
ItemId = resource.ItemId,
UsageThisMonth = resource.Usage,
UsageLastMonth = 0.0,
EffectiveRate = resource.EffectiveRate,
ResourceName = resource.ResourceName,
UnitOfMeasure = resource.UnitOfMeasure
};
}
//no data available
else
{
resources = new List<Resource>();
}
Problem:
This is very much code - should be less, any possible solutions failed so far
Thanks for helping!
public class ExampleClass
{
public int Id1 { get; set; }
public int Id2 { get; set; }
public int Usage { get; set; }
public int UsageThis { get; set; }
public int UsageLast { get; set; }
}
List<ExampleClass> listThisMonth = new List<ExampleClass>
{
new ExampleClass{Id1=1, Id2=1,Usage=7, UsageThis=1, UsageLast=0},
new ExampleClass{Id1=2, Id2=2,Usage=4, UsageThis=2, UsageLast=0},
new ExampleClass{Id1=3, Id2=3,Usage=1, UsageThis=3, UsageLast=0},
};
List<ExampleClass> listLastMonth = new List<ExampleClass>
{
new ExampleClass{Id1=1, Id2=1,Usage=3, UsageThis=1, UsageLast=1},
new ExampleClass{Id1=4, Id2=4,Usage=3, UsageThis=4, UsageLast=3},
new ExampleClass{Id1=2, Id2=2,Usage=1, UsageThis=8, UsageLast=6},
};
var result = listThisMonth.Select(a=>new {value=a, list=1})
.Union(listLastMonth.Select(a => new { value = a, list = 2 }))
.GroupBy(a => new { Id1 = a.value.Id1, Id2 = a.value.Id2 })
.Select(x => new ExampleClass
{
Id1 = x.Key.Id1,
Id2 = x.Key.Id2,
UsageThis = x.Any(o => o.list == 1) ? x.First(o => o.list == 1).value.Usage : 0,
UsageLast = x.Any(o => o.list == 2) ? x.First(o => o.list == 2).value.Usage : 0,
Usage = x.Sum(o=>o.value.Usage)
}).ToList();
//id1 id2 current last sum
//1 1 7 3 10
//2 2 4 1 5
//3 3 1 0 1
//4 4 0 3 3
It looks to me that what you're looking for is a full outer join. Unfortunately, it looks like LINQ doesn't have a construct for that. So, there are a few options: LINQ - Full Outer Join
For your scenario, it looks like you have some redundant code. You should be able to do the union using two outer joins to get the correct result set. For example:
// Left join the current month with the last month
var currentMonth =
from current in resourcesThisMonth
join last in resourcesLastMonth on new { current.SubscriptionId, current.ItemId } equals new { last.SubscriptionId, last.ItemId } into outer
from o in outer.DefaultIfEmpty()
select new Resource
{
SubscriptionId = current.SubscriptionId,
ItemId = current.ItemId,
UnitsThisMonth = current.Units,
UnitsLastMonth = o?.Units ?? 0, // Replace NULL with 0
EffectiveRate = current.EffectiveRate,
ResourceName = current.ResourceName,
UnitOfMeasure = current.UnitOfMeasure
};
// Reverse of the first join. Last month LEFT JOIN Current month
var lastMonth =
from last in resourcesLastMonth
join current in resourcesThisMonth on new { last.SubscriptionId, last.ItemId } equals new { current.SubscriptionId, current.ItemId } into outer
from o in outer.DefaultIfEmpty()
select new Resource
{
SubscriptionId = last.SubscriptionId,
ItemId = last.ItemId,
UnitsThisMonth = o?.Units ?? 0, // Replace NULL with 0
UnitsLastMonth = last.Units,
EffectiveRate = o?.EffectiveRate ?? last.EffectiveRate,
ResourceName = o?.ResourceName ?? last.ResourceName,
UnitOfMeasure = o?.UnitOfMeasure ?? last.UnitOfMeasure
};
// Union them together to get a full join
var resources = currentMonth.Union(lastMonth);

Recursive/Hierarchical Query in LINQ

Scenario is,
im using EntityFrame Work 6. I have a DB have table having structure below.
cat_id geo_id parent_id geo_name
Root 1 NULL Pakistan
Province 2 1 Punjab
District 3 2 Attock
City 4 3 Attock
City 5 3 Fateh Jang
City 6 3 Hasan Abdal
Table have hierarchical data in relational form,as you can see.
I want to traverse this hierarchy, want to specific parent level, If im at geo_id 6 then I want to go parent_id 3 and get value Attock or want to go to parent_id 2 and want to get value Punjab.
Moral of the story is,standing at any child,want traverse till specified parent or grand parent,not entire hierarchy. Below is code I have tried but it gives me only its immediate parent.
More Shortly, Want a LINQ query,which will return name of specified parent or grand parent,For Example. I can ask my query, "hey! im Hasan Abdal(City),tell me my Province"
Province = (from cp in db.geo_hierarchy
join mp in db.geo_hierarchy on cp.parent_id equals mp.geo_id
where cp.geo_name == risk.geo_hierarchy.geo_name
select mp.geo_name).FirstOrDefault()
see full code below,it used in inside LINQ query's select clause
Risklists = (from risk in db.risk_cat_detail
where risk.occurance_date.Value.Year==2014 && risk.occurance_date.Value.Month>=6 && risk.occurance_date.Value.Month<=9
select new risk_cat_detail_contract()
{
cat_id = risk.cat_id,
catdesc = risk.category_main.cat_name,
risk_cat_detail_id = risk.risk_cat_detail_id,
trans_date = risk.trans_date.Value,
occurance_date = risk.occurance_date.Value,
occurance_time = risk.occurance_time,
geo_id = risk.geo_id,
geo_desc = risk.geo_hierarchy.geo_name,
Province = (from cp in db.geo_hierarchy
join mp in db.geo_hierarchy on cp.parent_id equals mp.geo_id
where cp.geo_name == risk.geo_hierarchy.geo_name
select mp.geo_name).FirstOrDefault()
}).ToList<risk_cat_detail_contract>();
Help me out,Thanks in Advance
Try this:
var geo_hierarchy = new []
{
new { cat_id = "Root", geo_id = 1, parent_id = (int?)null, geo_name = "Pakistan", },
new { cat_id = "Province", geo_id = 2, parent_id = (int?)1, geo_name = "Punjab", },
new { cat_id = "District", geo_id = 3, parent_id = (int?)2, geo_name = "Attock", },
new { cat_id = "City", geo_id = 4, parent_id = (int?)3, geo_name = "Attock", },
new { cat_id = "City", geo_id = 5, parent_id = (int?)3, geo_name = "Fateh Jang", },
new { cat_id = "City", geo_id = 6, parent_id = (int?)3, geo_name = "Hasan Abdal", },
};
var map = geo_hierarchy.ToDictionary(x => x.geo_id);
Func<int, string, string> up = null;
up = (geo_id, cat_id) =>
{
var record = map[geo_id];
return
record.cat_id == cat_id
? record.geo_name
: (record.parent_id.HasValue
? up(record.parent_id.Value, cat_id)
: null);
};
var result = up(5, "Province"); // -> "Punjab"

Complicated Linq to SQL Query

I'm struggling to work out what the Linq-to-SQL syntax is for a particular query. I could do this easily in SQL, but I can't quite get the correct syntax in Linq.
I have parent and child records in two database tables, linked by a foreign key. I want my result to return rows based on these rules:
Return exactly 1 row per parent regardless of how many children exist.
Return null/zero values if the child doesn't exist.
Return related data from a child with a null condition. If more than one exists with a null condition then return just the first one.
Return a count of the number of child records with a non-null condition.
I have been playing around with this in .NET Fiddle for a while and I can't get it right. This is what I have so far (ignore the random descriptions!):
IEnumerable<Parent> parents = new Parent[] {
new Parent { ID = 1, Description = "Apple" },
new Parent { ID = 2, Description = "Orange" },
new Parent { ID = 3, Description = "Pear" },
new Parent { ID = 4, Description = "Banana" } };
IEnumerable<Child> children = new Child[] {
new Child { ID = 1, ParentID = 2, Description = "Mercury", Condition = null },
new Child { ID = 2, ParentID = 3, Description = "Venus", Condition = null },
new Child { ID = 3, ParentID = 3, Description = "Earth", Condition = null },
new Child { ID = 4, ParentID = 4, Description = "Mars", Condition = null },
new Child { ID = 5, ParentID = 4, Description = "Saturn", Condition = "> 5" } };
/// What goes here...?
var query = from p in parents
join c in children on p.ID equals c.ParentID into jc
from subchildren in jc.DefaultIfEmpty()
select new Item {
ParentID = p.ID,
Description = p.Description,
PrimaryChildID = subchildren == null ? 0 : subchildren.ID,
SubDescription = subchildren == null ? null : subchildren.Description,
ConditionalCount = 0};
foreach (var item in query)
Console.WriteLine("{0} {1} {2} {3} {4}",
item.ParentID,
item.PrimaryChildID,
item.Description,
item.SubDescription,
item.ConditionalCount);
The output I get from this is:
1 0 Apple 0
2 1 Orange Mercury 0
3 2 Pear Venus 0
3 3 Pear Earth 0
4 4 Banana Mars 0
4 5 Banana Saturn 0
but I want this:
1 0 Apple 0
2 1 Orange Mercury 0
3 2 Pear Venus 0
4 4 Banana Mars 1
Can anyone help me with the correct syntax for this query?
You don't need a left join in your case, you need a group join instead.
According to MSDN:-
The group join is useful for producing hierarchical data structures.
It pairs each element from the first collection with a set of correlated elements
from the second collection.
Do it like this:-
var query = from p in parents
join c in children
on p.ID equals c.ParentID into g
let firstNullElement = g.FirstOrDefault(x => x.Condition == null)
select new
{
ParentID = p.ID,
PrimaryChildID = firstNullElement != null ? firstNullElement.ID : 0,
Description = p.Description,
SubDescription = firstNullElement!= null ? firstNullElement.Description
: String.Empty,
ConditionalCount = g.Count(x => x.Condition != null)
};
Just to explain it properly, here is what will be generated before we project our actual required data using select new { }, (justifies the definition of Group Join):-
ParentId g
----------------------------------------------
1 null
2 ID = 1, ParentID = 2, Description = "Mercury", Condition = null
3 ID = 2, ParentID = 3, Description = "Venus", Condition = null
ID = 3, ParentID = 3, Description = "Earth", Condition = null
4 ID = 4, ParentID = 4, Description = "Mars", Condition = null
ID = 5, ParentID = 4, Description = "Saturn", Condition = "> 5"
Now, since g is holding an IEnumerable of Child elements we can apply filter, project data, count or do whatever we want, as we did in our final statement using select. And also, as we can see there is no point of data coming from different child element.
Here is the complete Working Fiddle.
This should do the thing
var query = (from p in parents
select new
{
ParentID = p.ID,
Description = p.Description,
PrimaryChildID = children.Where(c => c.ParentID == p.ID && c.Condition == null).Count() == 0 ? 0 : children.OrderBy(c=>c.ID).FirstOrDefault(c => c.ParentID == p.ID && c.Condition == null).ID,
SubDescription = children.Where(c => c.ParentID == p.ID && c.Condition == null).Count() == 0 ? null : children.OrderBy(c => c.ID).FirstOrDefault(c => c.ParentID == p.ID && c.Condition == null).Description,
ConditionalCount = children.Where(c => c.ParentID == p.ID && c.Condition != null).Count()
}).ToList();
This is my variant of query:
var query = from p in parents
join c in children on p.ID equals c.ParentID into jc
from subchildren in jc.DefaultIfEmpty()
select new
{
Parent = p,
Subchildren = subchildren
} into itemData
group itemData by itemData.Parent into g
select new Item
{
ParentID = g.Key.ID,
Description = g.Key.Description,
PrimaryChildID = g.Select(_ => _.Subchildren == null ? 0 : _.Subchildren.ID).FirstOrDefault(),
SubDescription = g.Select(_ => _.Subchildren == null ? null : _.Subchildren.Description).FirstOrDefault(),
ConditionalCount = 0
};

How find Max in a query with a join

I created this query, and I don't know how find the last date_attribution
var usertmp = from user in entity.inv_utilisateur
join userbadgetmp in entity.inv_utilisateur_badge on user.u_id equals userbadgetmp.u_id into gj
from userbadge in gj.DefaultIfEmpty()
select new UserEJ
{
u_id = (int) user.u_id,
name = user.name,
date_attrib = userbadge.date_attribution // here I want find the last date
};
for exemple if I have this 2 tables:
inv_utilisateur inv_utilisateur_badge
u_id name u_id date_attribution
1 name1 1 20130911
1 20130807
2 name2 2 20120608
3 name3
I need the result
u_id name date_attribution
1 name1 20130911
2 name2 20120608
3 name3
Edit 1
the type of the field are :
u_id : int,
name : string,
date_attribution : datetime
var usertmp = from user in entity.inv_utilisateur
join userbadgetmp in entity.inv_utilisateur_badge on user.u_id equals userbadgetmp.u_id into gj
from userbadge in gj.DefaultIfEmpty()
group userbadge by new{user.u_id, user.name} into g
select new UserEJ {
u_id = (int)g.Key.u_id,
name = g.Key.name,
date_attrib = g.Max(x => x!= null ? x.date_attribution : <a defaultvalue>)
}
you could also do
var usertmp = from user in entity.inv_utilisateur
let max_dt = (from userbadge in entity.inv_utilisateur_badge
where user.u_id == userbadge.u_id
select userbadge.date_attribution).Max()//??someDefaultvalue if you don't want null
select new UserEJ {
u_id = user.u_id,
name = g.name,
date_attrib = max_dt
}
Sorry for my answer but i am not used in the from clause:
var usertmp = entity.inv_utilisateur
.Join
(
entity.inv_utilisateur_badge,
x=>x.u_id,
x=>x.u_id,
(user,userbadge) => new
{
u_id = user.u_id,
name = user.name,
date_attrib = userbadge.date_attribution
}
)
.GroupBy(x=>new {x.u_id,x.name})
.Select
(
x => new
{
x.Key.u_id,
x.Key.name,
date_attrib = x.Max(z=>z.date_attrib)
}
);

Categories

Resources