LINQ QUERY TABLE - c#

The number increases by 1 in the database as a staff member views something.
Example
abab : 1
cbcb : 1
dcdc: 1
abab : 1
abab : 1
I want to print who viewed how much in the table.
Example
abab : 3
cbcb : 1
dcdc : 1
but it doesn't work the way I want. The code I wrote is below
Count = _viewHistoryRepository.GetByExpression(f => f.MemberId == c.MemberId).Sum(s=> s.ViewsCount)
Output:
abab : 3
abab : 3
abab : 3
cbcb : 1
dcdc: 1
I want each name to appear once. Thank you

You need to use GroupBy then:
IEnumerable<string> query = _viewHistoryRepository
.GroupBy(x => x.MemberId)
.Select(g => $"{g.Key} : {g.Sum(x => x.ViewsCount)}");

So apparently you have a class similar to this:
class StaffMemberView
{
public string Name {get; set;}
public int ViewCount {get; set;} // in your input always 1
... // other properties
}
If your input indeed always have a value 1, it is enough to make groups of StaffMemberviews that have the same value for property Name. In parameter resultSelector count the number of elements in each group:
IEnumerable<StaffMemberView> staffMemberViews = ...
var result = staffMemberViews.GroupBy(
// keySelector: make groups with the same value for Name:
staffMemberView => staffMemberView.Name,
// parameter resultSelector, for every Name, and all StaffMemberViews that
// have this Name, make one new:
(name, staffMembersViewsWithThisName) => new
{
Name = name,
ViewCount = staffMemberViewsWithThisName.Count(),
});
If parameter ViewCount sometimes is not 1, then it is not enough to just Count the StaffMemberViews in each group, but you have to Sum the values of ViewCount.
Parameter resultSelector changes:
(name, staffMembersViewsWithThisName) => new
{
Name = name,
ViewCount = staffMemberViewsWithThisName
.Select(staffMemberView => staffMemberView.ViewCount)
.Sum(),
});

Related

Find Common value against different id c# Linq

I have one table which is looking like this
ID
UserID
UserEncryptValue
1
1
abcd
2
2
1234
3
3
qwert
4
1
rstuv (Common value for user 1 and 2)
5
2
rstuv (Common value for user 1 and 2)
6
2
78901 (Common value for user 2 and 3)
7
3
78901 (Common value for user 2 and 3)
8
1
Hello123 (Common value for user 1,2 and 3)
9
2
Hello123 (Common value for user 1,2 and 3)
10
3
Hello123 (Common value for user 1,2 and 3)
Now I want to find if user 1 and 2 or 1, 2 and 3 have common value or not with use of Linq.
Assuming you're mapping that table to an actual object like 'UserData' like this:
public class UserData
{
public int Id { get; set; }
public int UserId { get; set; }
public string UserEncryptValue { get; set; }
}
You can get the common values like this (userData is a list of UserData and represents your data):
var searchId = 1;
var commonValues = userData.GroupBy(user => user.UserEncryptValue)
.Where(grp => grp.Count() > 1 && grp.Any(usr => usr.UserId == searchId))
.SelectMany(u => u);
This groups on the UserEncryptValue and only selects groups that have more than 1 value (has a match) and at least 1 of the user ids is equal to the searchId.
Table.Where(n => Table.Any(o => !(o === n) && o.UserEncryptValue == n.UserEncryptValue)).Select(n => n.UserID)
Will return a collection of user id's for members of collection Table where at least on other member of the table has the same value UserEncryptValue but is not the same object
Learn LINQ to understand how this works and what you can do to tweak it.
One way is to use GroupBy. In this case you would group by UserEncryptValue.
You can then examine each group and check which users are in each group.

Merging 2 rows from 2 different lists with same UserId?

If I have 2 different lists,
list1 contains:
UserId: fcec4d6c-c971-4690-90da-be8411dcf251 Col1: 32 Col2: 2 Col3: 0 Col4: 0
UserId: 783ffaa5-03ef-4883-80d2-0500ef489832 Col1: 50 Col2: 4 Col3: 0 Col4: 0
and list2 contains:
UserId: fcec4d6c-c971-4690-90da-be8411dcf251 Col1: 0, Col2: 0, Col3: 45, Col4: 50
If I want to merge these to lists, so that the result would end up being a UserDto list which contains:
UserId: fcec4d6c-c971-4690-90da-be8411dcf251 Col1: 32 Col2: 2 Col3: 34 Col4: 50
UserId: 783ffaa5-03ef-4883-80d2-0500ef489832 Col1: 50 Col2: 4 Col3: 0 Col4: 0
How would one go about doing that?
UserDto just contains something like
[JsonSchema(JsonObjectType.String, Format = "uuid")]
public Guid UserId { get; set; }
public int Col1 { get; set; }
public int Col2 { get; set; }
public int Col3 { get; set; }
public int Col4 { get; set; }
I've tried
list1.AddRange(list2);
list1.GroupBy(e => e.UserId, (key, g) => new { User = key, Columns = g.ToList() }).ToList();
return list1;
list1 returns 2 UserIds, where fcec4d6c-c971-4690-90da-be8411dcf251 now has a Columns list that contains 2 columns, one with col1 + col2 filled and col3 + col4 filled. Please note that these lists will contain a lot of these instances.
Edit 1: I should've made it more clear that I want the sum of these instances in the end. I have now received a proper solution.
Select proper aggregate function:
var result = list1.Concat(list2)
.GroupBy(e => e.UserId)
.Select(g => new User
{
UserId = g.Key,
Col1 = g.Max(x => x.Col1),
Col2 = g.Max(x => x.Col2),
Col3 = g.Max(x => x.Col3),
Col4 = g.Max(x => x.Col4),
})
.ToList();
You didn't specify why you didn't change Col1 and Col2, but changed Col3 and Col4. Do you always want to replace these two columns? Or do you only want to replace them if they have value zero? Or maybe you want to replace all columns with a zero value?
Anyway, first you need to get every list1Element with all zero or more list2Elements that have the same UserId.
Whenever you want to fetch "items with their sub-items", like Schools with their Students, Customers with their Orders, or list1Elements with their list2Elements, consider to use one of the overloads of Enumerable.GroupJoin.
As parameter keySelector use the properties that makes it "its list2Element"
IEnumerable<User> list1 = ...
IEnumerable<User> list2 = ...
var result = list1.GroupJoin(list2
list1User => list1User.UserId, // from every user in list1 take the UserId
list2User => list2User.UserId, // from every user in list2 take the UserId
// parameter resultSelector: from every user in list1, with the zero or more
// users from list2 that have the same UserId, make one new
(list1User, list2UsersWithSameId) => new
{
// decide what you want.
// Replace all 0 properties with the corresponding list2 column?
Col3 = (list1User.Col3 != 0) ? list1User.Col3 :
list2UsersWithSameId.Select(list2User => list2User.Col3)
.FirstOrDefault(),
So if listUser.Col3 not zero, use this Col3 value,
otherwise, from the zero or more list2UsersWithSameId take the Col3 and use the first or default. If there is a list2 user with same Id, you have got its Col3, if not, you get the value zero.
So the value is only replaced if Col3 is zero, and there is at least one list2 with the same Id. If there is none, Col3 remains zero.
Do the same for the other columns that you want to replace.
TODO: you didn't specify that UserId in list2 is unique. If not, it can be that a list item has more than one corresponding list2 item with the same userId. You have to decide which value to use: the first one? the largest one?

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!

C# Linq query condition

I have a table
I want to grab only the customer where the status = 1 for all rows. so in this example it would only grab John since Bob has status=2 for one record.
I would like to do this in linq c#. Do I need to group it first for all customers? and then have another query to check if it doesn't contain <> 2 then print it?
what would be the right way?
you were right on. Given:
class Customer
{
public string Name { get; set; }
public int Status { get; set; }
}
you'll want:
var names = customers.GroupBy(c => c.Name)
.Where(c => c.All(cc => cc.Status == 1))
.Select(c => c.Key)
.ToList();
Group By Name
Grab items where all Status = 1
Select the Names of the result
var data=customers.where(c => c.status!=2).select(c=>c.Customer).Tolist().distnict();

Filter a generic list based on another list

I have a generic list which needs to be filter based on another list (say, List<string>).
public class Model
{
public string ID { get; set;}
public string Make { get; set;}
}
List<Model> lstModel = new List<Model>();
And the lstModel is as follows
ID Make
---- -----------
5 MARUTI
4 BENZ
3 HYUNDAI
2 HONDA
1 TOYOTA
And i have another list which contains only car makers,ie
List<string> lstMakers = new List<string>() {"MARUTI", "HONDA"};
1) I need to filter lstModel which contains only items in lstMakers.
The output would be
ID Make
---- -----------
5 MARUTI
2 HONDA
2) Based on output (1), need another list of ids with 1 increment to each item in descending order,
The output would be List<int> ie,
6
5
3
2
Note: Using lambda expression / linq is more preferable
1 )
var list1 = lst.Where(x=>lstMakers.Contains(x.Make)).ToList();
2)
var list2 = list1.Select(x=>int.Parse(x.ID)+1)
.Concat(list1.Select(x=>int.Parse(x))
.OrderByDescending(x=>x)
.ToList();
Use Enumerable.Join and OrderByDescending:
var models = from maker in lstMakers
join model in lstModel
on maker equals model.Make
select model;
List<int> result = models
.Select(m => int.Parse(m.ID) + 1)
.OrderByDescending(i => i)
.ToList();
However, this selects two ints since only two models match. Your result contains 4 ints. I assume that your result is not related to your sample, is it?
but i need both the item and its incremental value,...
Now it's clear, use Enumerable.SelectMany with an array:
List<int> result = models
.Select(m => int.Parse(m.ID))
.SelectMany(id => new int[]{ id, id + 1 })
.OrderByDescending(id => id)
.Distinct()
.ToList();

Categories

Resources