LINQ Group By and Intersection between groups C# - c#

I have the following list into C#:
table_schema | table_name | field_name | field_type
public tableA fieldA character varying
public tableA fieldB timestamp
public tableA fieldC bytea
public tableB fieldA character varying
public tableB fieldD integer
other tableC fieldA character varying
other tableC fieldE integer
So the field with name fieldA and type character varying exists to all.
The output should be a list object :
field_name | field_type
fieldA character varying

I suggest GroupBy and then Aggregate all these groups while Intersecting their content:
var list = ...
var result = list
.GroupBy(item => (item.table_schema, item.table_name),
item => (item.field_name, item.field_type))
.Select(group => group.AsEnumerable())
.Aggregate((current, item) => current.Intersect(item))
.ToList(); // <- Let's have a list of tuples
The only trick is line
.Select(group => group.AsEnumerable())
We don't want to aggregate by IGrouping<K, V> but by more general IEnumerable<V>

Related

How to C# Linq Order by using list of strings similar to MySql FIELD

I have the following
List<WorkItemHeader>
WorkItemWorkItemHeader(string company, string division, string customerNumber, string imgCode, int sequence, string orderNumber, int lineNumber, DateTime importDate, int processType, int operatorID, int typeset, string product)
I would like to order my list by multiple properties (by Division, ImportDate, OrderNumber, LineNumber)
Division contains (ABC, XYZ, DEF, HIJ)
My requirement (and question) is, Division needs to be sorted by Division containing: (XYZ, ABC) first then by ImportDate, OrderNumber, LineNumber.
MySql has FIELD()
ORDER BY FIELD(position,'forward', 'midfielder', 'defender', 'goalkeeper')
T-SQL has CASE WHEN
ORDER BY CASE Position WHEN "forward" THEN 1
WHEN "defender" THEN 2
WHEN "midfielder" THEN 3
WHEN "goalkeeper" THEN 4 END
How can I simulate the sorting using Linq?
It sounds like you want to just get Division XYZ and ABC first, order those by the fields you specified, then order the rest, and then combine those results? You did not specify how you wanted to order the remaining divisions or the other fields, so I just did the default ascending order.
var firstOrder = header.Where(d => d.Division == "XYZ" || d.Division == "ABC").OrderByDescending(c => c.Division).ThenBy(d => d.ImportDate).ThenBy(d => d.OrderNumber).ThenBy(d => d.LineNumber).ToList();
var secondOrder = header.Where(d => d.Division != "XYZ" && d.Division != "ABC").OrderBy(c => c.Division).ThenBy(d => d.ImportDate).ThenBy(d => d.OrderNumber).ThenBy(d => d.LineNumber).ToList();
firstOrder.AddRange(secondOrder);

C# Lambda Join Retrieve First Row Values

I have two tables, Table1 and Table2. Table1 has 1 to many relationship with Table2.
Table1 has ListId, ListName
Table2 has FirstName, LastName, Phone, ListId, CustomField1, CustomField2
What I want to retrieve is All rows from Table1 but only retrieve CustomField2 value of Table2 for only 1st row.
The existing query I have below is retrieving me all rows from Table2 which I do not want.
var result = _db.Lists
.Join(_db.ListUsers, c => c.ListID, d => d.ListID, (c, d) => new { c, d });
My final resultset need to look like this
Table1.ListId, Table1.ListName, Table2.CustomField2
1, first list, "abc"
2, second list, "def"
This should do the trick, get only the first record on the right table:
from i in _db.Lists
let p = _db.ListUsers.Where(p2 => i.ListID == p2.ListID).FirstOrDefault()
select new
{
ListID = i.ListID,
ListName = i.ListName,
CustomField2 = p.CustomField2
}
With lambda expression, it would be:
_db.Lists
.Select (
i =>
new
{
i = i,
p = _db.ListUsers
.Where (p2 => i.ListID == p2.ListID))
.Take(1)
.FirstOrDefault()
})
.Select (
results =>
new
{
ListID= results.i.ListID,
ListName = results.i.ListName,
CustomField2 = results.p.CustomField2
}
)
From what I read, the result you want to achieve is retrieve a list of results contains All columns from Table1 & 1 column from Table2 (Not rows).
There are few ways to do this. I would use create a DTO class to retrieve my results. And in the select , you would need to specifically list out the item in your select result.
For example,
Create a DTO class
public class DTOListResult
{
public string XXX {get; set;}
...
}
Then in your result, you can write in this way.
var result = (from a in _db.Lists select new DTOListResult { XXX = _db.table2.ID,
xxx = a.ID,
XXX = a.XX});

Entity Framework - .Include doesn't load all records

I have this a database with these entities:
public class User
{
public GUID UserId { get; set;}
public IEnumerable<Item> items { get; set;}
}
public class Item
{
public GUID ItemId { get; set;}
public GUID ownerId { get; set;}
public int boughtCount{ get; set;}
}
I need to return the list of users that have items ordered by the items bought the most.
So for example if we have this users:
A: userId: ..
items: 1. itemId: .. | boughtCount: 2
2. itemId: .. | boughtCount: 1
B: userId: ..
items: 1. itemId: .. | boughtCount: 7
C: userId: ..
items: 1. itemId: .. | boughtCount: 3
D: userId: ..
items: none
The query needs to return the users in the following order: B,C,A (D is not returned as he doesn't have any items)
I am using the following query:
users = await _context.Items.OrderByDescending(c => c.BoughtCount)
.Join(_context.Users,
i => i.OwnerId,
u => u.Id,
(i, u) => new { i, u })
.OrderByDescending(x => x.i.BoughtCount)
.Select(x => x.u)
.Distinct()
.Skip(skip)
.Take(take)
.Include(u => u.Items)
.ToListAsync();
This query returns the users in the correct order, but my problem is that for each user it returns maximum of 15 of the items he has, so if for example user A would have 30 items, I will only get his first 15.
What is this 15 items limit?
Am I doing something that cause this limit to come or it's just "hard coded" somewhere?
If so, how do I remove/change the limit?
Note: My sql database is hosted in Azure.
UPDATE:
This is the generated sql query from my linq query:
SELECT [I].[ItemId], [I].[ownerId], [I].[boughtCount]
FROM [Items] AS [I]
INNER JOIN (
SELECT DISTINCT [t0].*
FROM (
SELECT DISTINCT [u].[UserId]
FROM [Items] AS [I]
INNER JOIN [User] AS [u] ON [c].[ownerId] = [u].[UserId]
ORDER BY [u].[UserId]
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
) AS [t0]
) AS [u] ON [I].[ownerId] = [u].[UserId]
Thanks!

Sorting a list based on another attribute in another list

I have the objects as below:
public class CustomerSequence
{
public string CustomerName { get; set; }
public int Sequence { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Component { get; set; }
}
Let's say I have 2 Lists Object
Customer: CustomerSequence:
Id Name Component CustomerName Sequence
1 AAA AAAAAA AAA 2
2 BBB BBBBBBB BBB 4
3 CCC CCCCC CCC 1
DDD 3
As you can see there is no DDD in List.
I want to sort the List Customer based on the List CustomerSequence
Result is:
Customer:
Id Name Component
3 CCC CCCCC
1 AAA AAAAAA
2 BBB BBBBBBB
Anyone can help me please.
Join both sequences on customer name, then order by sequence value:
from c in customers
join cs in customerSequences
on c.Name equals cs.CustomerName
orderby cs.Sequence
select c;
Lambda syntax is not that beautiful, and it will look like
customers.Join(customerSequences,
c => c.Name, cs => cs.CustomerName, (c,cs) => new { c, cs })
.OrderBy(x => x.cs.Sequence)
.Select(x => x.c)
Internally join uses lookup for second sequence, which is much more effective then linear search with Where.
If it is possible that there is no CustomerSequencs matching customer, or there is more than one match, then use group join:
from c in customers
join cs in customerSequences
on c.Name equals cs.CustomerName into g
orderby g.Select(cs => cs.Sequence).FirstOrDefault()
select c
This query uses 0 form missing sequences, and first matched value if there is more than one sequence for customer.
Try this
Customer.OrderBy(x => CustomerSequence.Where(y => y.CustomerName == x.Name)
.Select(y => y.Sequence)
.FirstOrDefault())
Alternatively you can use a join which would be better if the source was a database
var sorted =
from c in customer
join csj in customerSequence on c.Name equals csj.CustomerName into customerSequenceJoined
from cs in customerSequenceJoined.DefaultIfEmpty()
orderby cs == null ? 0 : cs.Sequence
select c;
The cs == null ? 0 : cs.Sequence deals with the case when there is no matching record in the sequence collection. You could use int.MaxValue if you want these items to appear last.
Use Join
var customers = from cust in Customer
join cust_seq in CustomerSequence
on cust.Name equals cust_seq.CustomerName
orderby cust_seq.Sequence
select cust;
I tend to use a dictionary for this sort of thing.
var customerSequence =
customerSequences
.ToDictionary(x => x.CustomerName, x => x.Sequence);
var sortedCustomers =
customers
.OrderBy(x => customerSequence[x.Name])
.ToList();

Ranking. Linq to sql question

I have a table of orders made by persons:
Orders
{
Guid PersonId,
int Priority,
Guid GoodId
}
Priority is some integer number. For example:
AlenId 1 CarId
DianaId 0 HouseId
AlenId 3 FoodId
DianaId 2 FlowerId
I want to retrieve highest priority orders for each person:
AlenId 1 CarId
DianaId 0 HouseId
In T-SQL I'll use ranking, how can I get the same result in Linq-2-Sql ?
Thank you in advance!
Something like this:
var query = from order in context.Orders
orderby order.Priority
group order by order.PersonId into personOrders
select personOrders.First();
I believe that should work, but I don't know how well-defined it is, in terms of the ordering post-grouping. This would also work, although it's slightly uglier:
var query = from order in context.Orders
group order by order.PersonId into personOrders
select personOrders.OrderBy(order => order.Priority).First();
Or using just dot notation:
var query = context.Orders
.GroupBy(order => order.PersonId)
.Select(group => group.OrderBy(order => order.Priority)
.First());

Categories

Resources