Flatten an ObservableCollection - c#

I have a collection like this:
Order //Collection
|-OrderId
|-DateOfOrder
|-PartyName
|-OrderDetails //Collection
| |-ItemName
| |-Quantity
| |-Rate
| |-Amount
|-Dispatch //Collection
| |-InvoiceNo
| |-DateOfDispatch
| |-DispatchDetails //Collection
| | |-ItemName
| | |-Quantity
| | |-Rate
| | |-Amount
Now I want to flatten this collection, so that I can show data in below mentioned pattern:
OrderId | DateOfOrder | PartyName | InvoiceNo | DateOfDispatch | Dispatch ItemName | Dispatch Quantity | Dispatch Rate | Dispatch Amount
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
I have tried:
Orders = new ObservableCollection<Order>(orderService.GetAllOrders()
.SelectMany(x => x.Dispatches)
.SelectMany(x => x.DispatchDetails)
.ToList()
);

The relation between OrderDetails and DispatchDetails is not clear to me, and DispatchItemTransactions seems to be missing from your data structure. Anyway, I hope you find this simple approach useful:
foreach(var order in Orders)
foreach(var dispatch in order.Dispatches)
foreach(var dispatchDetail in dispatch.DispatchDetails)
{
// now construct your record object from order.OrderId, order.DateOfOrder, ... , dispatchDetail.Amount
}

For this to work you'll need to construct new Order and Dispatch objects. Also query syntax will make this much easier to read.
Orders = new ObservableCollection<Order>(
from o in orderService.GetAllOrders
from d in o.Dispatches
from dd in d.DispathDetails
select new Order
{
OrderId = o.OrderId,
DateOfOrder = o.DateOfOrder,
PartyName = o.PartyName,
Dispatches = new List<Dispatch>
{
new Dispatch
{
InvoiceNo = d.InvoiceNo
DateOfDispatch = d.DateOfDispatch
DispatchDetails = new List<DispatchDetail> { dd }
}
}
});
Though instead of a collection of Order you might want to just use an anonymous class instead
from o in orderService.GetAllOrders
from d in o.Dispatches
from dd in d.DispathDetails
select new
{
OrderId = o.OrderId,
DateOfOrder = o.DateOfOrder,
PartyName = o.PartyName,
InvoiceNo = d.InvoiceNo
DateOfDispatch = d.DateOfDispatch,
DispatchItemName = dd.ItemName,
DispatchQuantity = dd.Quantity,
DispatchRate = dd.Rate,
DispatchAmount = dd.Amount
}

Related

Linq - join two tables and count

Have two tables:
Catalog
|----------|----------|-----------|
| Id | Name | CreatedBy |
|----------|----------|-----------|
| 1 | Catalog1 | 1 |
| 2 | Catalog2 | 1 |
| 3 | Catalog3 | 1 |
| 4 | Catalog4 | 2 |
|----------|----------|-----------|
TemplateOnCatalog
|------------|-----------|
| TemplateId | CatalogId |
|------------|-----------|
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 4 |
|------------|-----------|
Using c# and Linq, how to get a list of all the catalogs, where CreatedBy = 1, and count the number of templates in the catalog. If no templates, the count value should be 0 (or empty).
Expected result:
|------------|-------------|-------------------|
| CatalogId | CatalogName | NumberOfTemplates |
|------------|-------------|-------------------|
| 1 | Catalog1 | 2 |
| 2 | Catalog2 | 3 |
| 3 | Catalog3 | 0 |
|------------|-------------|-------------------|
I try the following, but it doesn't take catalogs without templates:
var templateCatalogs =
from templateCatalog in db.Catalog.AsNoTracking()
join totc in db.TemplateOnCatalog
on templateCatalog.Id equals totc.CatalogId
where
templateCatalog.CreatedBy == 1
orderby templateCatalog.Name
group new { templateCatalog, totc }
by new { templateCatalog.Name, templateCatalog.Id } into result
select new
{
CatalogId = result.Key.Id,
CatalogName = result.Key.Name,
NumberOfTemplates = result.Count()
};

LINQ select out list of values and map into one field property in the nested class structure

Animal:
+----------+---------+--------+
| animalId | animal | typeId |
+----------+---------+--------+
| 1 | snake | 1 |
| 2 | cat | 2 |
+----------+---------+--------+
AnimalType:
+--------+----------+
| typeId | type |
+--------+----------+
| 1 | reptile |
| 2 | mammal |
+--------+----------+
AnimalBody:
+--------+-------+----------+
| bodyId | body | animalId |
+--------+-------+----------+
| 1 | tail | 1 |
| 2 | eye | 1 |
| 3 | tail | 2 |
| 4 | eye | 2 |
| 5 | leg | 2 |
+--------+-------+----------+
Table relation:
Animal.typeId = AnimalType.typeId
Animal.animalId = AnimalBody.animalId
I need to output them into JSON format as below:
{
animalId: 1,
animal: "snake",
type: "reptile",
body: {
"tail", "eye"
}
},
{
animalId: 2,
animal: "cat",
type: "mammal",
body: {
"tail", "eye", "leg"
}
}
How can I achieve this with pure LINQ clauses instead of method?
I have tried:
from animal in db.Animal
join animalType in db.AnimalType on animal.typeId equals animalType.typeId
select new
{
animalId = animal.animalId,
animal = animal.animal,
type = animalType.type,
body = ?
};
Assuming you want the body element to be an array of body parts, here's what you should do:
Join Animals with AnimalTypes:
var animalsWithType = db.Animals.Join(
animal => animal.typeId,
animalType => animalType.typeId,
(animal, type) => new { animal, type });
Afterwards, GroupJoin animalsWithType with AnimalBody elements:
var result = animalsWithType.GroupJoin(db.AnimalBodies,
animalWithType => animalWithType.animal.animalId,
body => body.animalId,
(animalWithType, bodyParts) => new
{
animalId = animalWithType.animal.animalId,
animal = animalWithType.animal.animal,
type = animalWithType.type.type,
body = bodyParts.Select(part => part.body)
});
Now, just export the result to JSON and you should be set.

how to assign colour to duplicate values in a list

how to assign colour to duplicate values in a list
This my table
| user_id | account_no | zip | date |
| 1 | 123 | 55555 | 12-DEC-09 |
| 1 | 123 | 66666 | 12-DEC-09 |
| 1 | 123 | 55555 | 13-DEC-09 |
| 2 | 456 | 77777 | 14-DEC-09 |
| 2 | 456 | 77777 | 14-DEC-09 |
| 2 | 789 | 77777 | 14-DEC-09 |
| 2 | 789 | 77777 | 14-DEC-09 |
You can assign a color in this way:
var userIdGroups = db.TableName.GroupBy(x => x.user_id).AsEnumerable();
var itemsWithColors = userIdGroups
.SelectMany(g => g.Select((x, index) => index == 0
? new { Item = x, Color = Color.Black }
: new { Item = x, Color = Color.Red }));
Now use a foreach loop to process this query and add these items to your UI control.

linq Group By from DataTable

I have DataTable Like this
Thank you Bob Vale for your help
what is (Select(X,i) mean in your linq,
but as i made a mistake in my table
I have this
No | Size | Type | FB | FP
----------------------------------------
100 | 2 | typeA | FB1 | A1
101 | 3 | typeB | FB1 | A1
101 | 4 | typec | FB1 | A1
103 | 4 | typeC | FB2 | A2
103 | 5 | typeD | FB2 | A2
103 | 6 | typeE | FB2 | A2
I want to have some thing like that
No | Size | Type | FB | FP
---------------------------------
100 | 2 | typeA | FB1 | A1
101 | 3 | typeB | FB1 | A1
| 4 | typec | |
103 | 4 | typeC | FB2 | A2
| 5 | typeD | |
| 6 | typeE | |
How can I make it? I can make Group By
var result = from row in cableDataTable.AsEnumerable()
group row by new
{
FB = row.Field<string>("FB"),
FP = row.Field<string>("FP"),
Size = row.Field<int>("Size"),
Type = row.Field<int>("Type"),
no= row.Field<int>("no"),
} into g
select new
{
FB = g.Key.FB,
FP = g.Key.FP,
Size = g.Key.Size,
Type = g.Key.Type
no= g.Key.no
};
but it that could't give the result
thank you for your attention
How about this:
// First declare a conversion from the DataTable to an anon type
var rows = cableDataTable.AsEnumerable()
.Select(x => new {
Size = x.Field<int>("Size"),
Type= x.Field<string>("Type"),
FB = x.Field<string>("FB"),
FP = x.Field<string>("FP")
});
// Now use group by, ordering and select many to select the rows
var result = rows.GroupBy (row => new {row.FB, row.FP} )
.OrderBy (g => g.Key.FB)
.ThenBy(g => g.Key.FP)
.SelectMany(g => g.OrderBy(row => row.Size)
.Select((x,i) =>
new {
Size = x.Size,
Type = x.Type,
FB = (i==0) ? x.FB : null,
FP= (i==0) ? x.FP : null
}));
You can use linq query as
var result = cableDataTable.AsEnumerable().GroupBy(g => new { g.FB, g.FP}).Select(x => x);

Merging 2 lists and sum several properties using LINQ

I have an class which contains the following properties:
public class SomeClass()
{
public Int32 ObjectId1 {get;set;}
public Int32 ObjectId2 {get;set;}
public Int32 ActiveThickeness {get;set;}
public Int32 ActiveFilterThickness {get;set;}
}
I also have 2 lists:
List<SomeClass> A
List<SomeClass> B
List A has data:
| ObjectId1 | ObjectId2 | ActiveThickness | ActiveFilterThickness |
-------------------------------------------------------------------
| 1 | 3 | 50 | 0 |
------------------------------------------------------------------
| 1 | 2 | 400 | 0 |
-------------------------------------------------------------------
| 4 | 603 | 27 | 0 |
-------------------------------------------------------------------
List B has data:
| ObjectId1 | ObjectId2 | ActiveThickness | ActiveFilterThickness |
-------------------------------------------------------------------
| 1 | 3 | 0 | 13671 |
------------------------------------------------------------------
| 1 | 2 | 0 | 572 |
-------------------------------------------------------------------
| 29 | 11 | 0 | 4283 |
-------------------------------------------------------------------
I want to merge A and B (using LINQ if possible) into List C of SomeCalss which contains data as followed:
| ObjectId1 | ObjectId2 | ActiveThickness | ActiveFilterThickness |
-------------------------------------------------------------------
| 1 | 3 | 50 | 13671 |
------------------------------------------------------------------
| 1 | 2 | 400 | 572 |
-------------------------------------------------------------------
| 29 | 11 | 0 | 4283 |
-------------------------------------------------------------------
| 4 | 603 | 27 | 0 |
-------------------------------------------------------------------
How can I achieve that?
Use GroupBy to group common objects and Sum to sum required properties
var ab = A.Concat(B).GroupBy(x => new
{
x.ObjectId1,
x.ObjectId2
});
var result = ab.Select(x => new SomeClass
{
ObjectId1 = x.Key.ObjectId1,
ObjectId2 = x.Key.ObjectId2,
ActiveFilterThickness = x.Sum(i => i.ActiveFilterThickness),
ActiveThickeness = x.Sum(i => i.ActiveThickeness)
});
See LINQ - Full Outer Join (SO).
By doing a left outer join and a right outer join, and then taking the union of those two, you should get what you're looking for.
var leftOuterJoin = from someclass1 in A
join someclass2 in B
on someclass1.ObjectID2 equals someclass2.ObjectID2
into temp
from item in temp.DefaultIfEmpty(new SomeClass(){ objectID1 = someclass1.objectID1, ... })
select new SomeClass()
{
...
};
var rightOuterJoin = from someclass2 in B
join someclass1 in A
on someclass1.ObjectID2 equals someclass2.ObjectID2
into temp
from item in temp.DefaultIfEmpty(new SomeClass(){ objectID1 = someclass1.objectID1, ... })
select new SomeClass()
{
...
};
var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);

Categories

Resources