How to create a moq unit test when grouping by class - c#

This is my code:
var data = context.GetAll<UserRole>()
.GroupBy(x => new RoleGroup { RoleId = x.RoleId, AccessEnum = x.AccessEnum })
.Where(x => x.Count() > 1);
This is the data mock:
var userRoles = new List<UserRole>
{
new UserRole { Id = 1, RoleId = 1, AccessEnum = AccessEnum.Full },
new UserRole { Id = 2, RoleId = 1, AccessEnum = AccessEnum.Full },
new UserRole { Id = 3, RoleId = 2, AccessEnum = AccessEnum.ReadOnly },
new UserRole { Id = 4, RoleId = 2, AccessEnum = AccessEnum.Full },
new UserRole { Id = 5, RoleId = 2, AccessEnum = AccessEnum.ReadOnly }
};
mockContext.Setup(x => x.GetAll<UserRole>()).Returns(userRoles.AsQuerable());
The GroupBy works fine when using the system. However when I run a unit test it returns each record individually. If I change the GroupBy to an anonymous object, it does work:
.GroupBy(x => new { x.RoleId, x.AccessEnum })
But I need to pass the list into another method. So I need to define the key as a RoleGroup.
Is there a way to get this working by keeping the class in the GroupBy?

Related

How to get aggregated values from a collection using values from the same collection as predicate

I have a list containing Employee Model Objects.
public List<EmployeeModel> EmployeeData()
{
return new List<EmployeeModel>()
{
new EmployeeModel(){ EmpID = 1, EmpSSN = 11, LName = "Motor", FName = "Mouse" },
new EmployeeModel(){ EmpID = 2, EmpSSN = 11, LName = "Motor", FName = "Mouse" },
new EmployeeModel(){ EmpID = 3, EmpSSN = 11, LName = "Motor", FName = "Mouse" },
new EmployeeModel(){ EmpID = 1, EmpSSN = 12, LName = "Cat", FName = "Auto" },
new EmployeeModel(){ EmpID = 2, EmpSSN = 12, LName = "Cat", FName = "Auto" },
};
}
I need to list each employee and their total EmpSSN occurrence so that the output will look like this:
Last Name: Mouse. Total EmpSSN: 3
Last Name: Cat. Total EmpSSN: 2
I can do something like this to get the names:
var name = data.EmployeeData().Select(x => x.LastName).Distinct();
However, I am not certain how to get the EmpSSN Count without writing extraneous code or using the same list twice, given I will not know the data in the list or have arguments to pass.
Rather than using Distinct, use GroupBy:
var name = data.EmployeeData()
.GroupBy(x => x.LastName)
.Select(g => new {
LastName = g.Key
, TotalEmpSsn = g.Count()
});
Since LastName is used as the group's key, Select gets groups combining records with identical last name. If you are looking to coult items within the group where a specific predicate would be true (e.g. EmpSsn above a certain number, etc.) you can supply that predicate to the Count() method.
I would group them first by LastName then call Sum() on the EmpSSN like so:
var data = EmployeeData()
.GroupBy(e => e.LastName)
.Select(e => new {
EmpID = e.Key,
EmpSSN = e.Select(emp => emp.EmpSSN).Sum()
});

Linq SQL Search - From tags with more matches

I'm writing a tag search in C# MVC, but I'm only able to get all the results that have one of the words. - The output should be only where all the input words matches, and exclude if e.g. 2 words are in the input, but only one of them matches.
My code so far:
List<String> list = Request["tags"].Split(' ').ToList();
KDBEntities q = new KDBEntities();
var query = (from tag in q.KDB_tags join question in q.KDB_questions on tag.question_id equals question.id where list.Any(x => x.Equals(tag.tag)) select question);
var Rquery = query.GroupBy(x => x.id).Select(grp => grp.FirstOrDefault()).ToList();
return View(Rquery);
I've been trying to figure this out for quite a while, but with no luck.
Hope this makes sense, and any of you can help me.
Tags list:
List<TagObj> tags = new List<TagObj>()
{
new TagObj() { Id = 1, QuestionId = 1, Tag = "news" },
new TagObj() { Id = 2, QuestionId = 1, Tag = "sports" },
new TagObj() { Id = 3, QuestionId = 1, Tag = "famous" },
new TagObj() { Id = 4, QuestionId = 2, Tag = "news" },
new TagObj() { Id = 5, QuestionId = 2, Tag = "sports" },
new TagObj() { Id = 6, QuestionId = 3, Tag = "news" },
new TagObj() { Id = 7, QuestionId = 4, Tag = "funny" },
};
Questions list:
List<QuestionObj> questions = new List<QuestionObj>()
{
new QuestionObj(){ QuestionId = 1, Question = "Whats up footballers?" },
new QuestionObj(){ QuestionId = 2, Question = "These are famous news?" },
new QuestionObj(){ QuestionId = 3, Question = "Read all about it?" },
new QuestionObj(){ QuestionId = 4, Question = "You know whats funny?" }
};
These are incoming tags from the request:
var incomingTags = new List<string>() { "news", "sports" };
These are the queries:
var query = from t in tags
join q in questions on t.QuestionId equals q.QuestionId
where incomingTags.Contains(t.Tag)
select new { question = q, tag = t };
var result = query.
GroupBy(g => g.question.QuestionId).
Where(g => g.ToList().Select(l => l.tag.Tag).SequenceEqual(incomingTags)).
Select(s => s.First().question).ToList();

Return List that Contains All Ids from an int list

I have a list of ids:
var IdList = new int[]{1, 2};
I also have a list of users:
var userList = new List<User>()
{
new User() {Id = 1, Name = "User1" },
new User() {Id = 1, Name = "User2" },
new User() {Id = 2, Name = "User2" },
new User() {Id = 1, Name = "User3" },
new User() {Id = 1, Name = "User4" },
new User() {Id = 2, Name = "User4" }
};
I want to get a list of users that must contain all the Ids from the IdList. So in this example I want to return User2 and User4. I've seen other subset examples that are just using Except and return boolean and even when adapting to my needs do not produce the correct results. I also saw one marked as duplicate (Similar Question) which is trying to do exactly this but did not agree that it was a duplicate and was never truly answered. I have attempted:
userList.Where(u => IdList.All(i => i == u.Id)).ToList();
that will not return anything.
Your question is a little confusing. You say you want to get a list of users that must contain all the Ids from the IdList and your expected output is User 2 and 4. That does not makes sense because your IdList has 1 and 2.
Also you have more than one record with Id 1. User1, User2 and User3 has same Id. What is the pattern to get one record from this ?
Assuming you do not have duplicate data and you want subset of items based on the items int eh idList, You can use LINQ Contains method.
var IdList = new int[]{1, 2};
var userList = new List<User>()
{
new User() {Id = 1, Name = "User1" },
new User() {Id = 2, Name = "User2" },
new User() {Id = 3, Name = "User3" },
new User() {Id = 4, Name = "User4" }
};
var subSet = userList.Where(d=>IdList.Contains(d.Id);
//subSet will have records for User1 and User2
Use Bellow 1Line linq code.
var q = userList.GroupBy(c => c.Name).Where(c => IdList.All(ccc => userList.Where(cc => cc.Name == c.Key).Any(cc => cc.Id == ccc))).ToList();
and this code return User2 and User4
Well, this is not elegant, but works:
List<string> result = new List<string>();
result = userList.Where(x => x.Id == IdList[0]).
Select(x => x.Name).ToList();
for(int i =1; i<IdList.Count();i++)
{
result = userList.Where(x => x.Id == IdList[i]).
Select(x => x.Name).ToList().
Intersect(result).ToList();
}

Dynamic linq query with nested groups

I'm trying to create nested group with dynamic query.
Following are my collection of data
var invoices = new List < Purchase > () {
new Purchase() {
Id = 1, Customer = "a", Date = DateTime.Parse("1/1/2009")
}, new Purchase() {
Id = 2, Customer = "a", Date = DateTime.Parse("1/2/2009")
}, new Purchase() {
Id = 3, Customer = "a", Date = DateTime.Parse("1/2/2009")
}, new Purchase() {
Id = 4, Customer = "b", Date = DateTime.Parse("1/1/2009")
}, new Purchase() {
Id = 5, Customer = "b", Date = DateTime.Parse("1/1/2009")
}, new Purchase() {
Id = 6, Customer = "b", Date = DateTime.Parse("1/2/2009")
}
};
This linq query is returning the desired result.
var tree = invoices.GroupBy(x => x.Date).Select(x => new
{
Key = x.Key,
Items = x.GroupBy(y => y.Customer).Select(y => new
{
Key = y.Key,
Items = y
})
}).ToList();
Below is the output of the above linq query
But I just need to group different columns in different order.
So that I try to create dynamic linq query. But my code block result not same as my previous linq query.
var groupedInvoiceItems = invoices.AsQueryable().GroupBy("new (Date, Customer)", "it");
You could do this with Generics. Just Pass in your Lambda to a generic method.
Something like:
private IEnumerable<PurchaseGrp> BuildList<TSource>(IQueryable<TSource> allRecords,
Func<TSource, string> selector)
{
var result = allRecords.GroupBy(x = > x.selector(x));
return result;
}
The return type could be a new Grouped type PurchaseGrp or the same as your source (Purchase).

Is there a better LINQ Query to do this?

Lets say I have a flat list of objects, each of which has a person's name, and a single Role they're in, like so:
var People = new[] {
new PersonRole(){ Name = "Adam", Role = "R1" },
new PersonRole(){ Name = "Adam", Role = "R2" },
new PersonRole(){ Name = "Adam", Role = "R3" },
new PersonRole(){ Name = "Bob", Role = "R1" },
};
Now, is there a direct way to get this into a Dictionary<string, List<string>> based on Name and Role (obviously). I did it in two steps, like below, but I have to think there's a more direct way.
Dictionary<string, List<string>> resultLookup =
People.Select(p => p.Name).Distinct().ToDictionary(str => str, str => new List<string>());
People.ForEach(p => resultLookup[p.Name].Add(p.Role));
Thanks!
Dictionary<string, List<string>> dictionary = people.GroupBy(p => p.Name).ToDictionary(g => g.Key, g => g.Select(p => p.Role).ToList());
Untested, but I think that should work...
EDIT Tested it now, and that does in fact work.
This should do it:
var people = new[] {
new { Name = "Adam", Role = "R1" },
new { Name = "Adam", Role = "R2" },
new { Name = "Adam", Role = "R3" },
new { Name = "Bob", Role = "R1" },
};
var r = from p in people
group p by p.Name
into g
select new {
Name = g.Key,
Roles = g.Select(p => p.Role).ToList()
};
var d = r.ToDictionary(k => k.Name, e => e.Roles);
var dict = People.ToLookup(p=>p.Name, p=>p.Role)
.ToDictionary(it=>it.Key, it=>it.ToList());
var result = People.GroupBy(a => a.Name).ToDictionary(a => a.First().Name, b => b.Select(c => c.Role).ToList());
People
.GroupBy( p => p.Name )
.ToDictionary( p => p.Key, p => p.Select(pr => pr.Role).ToList() )

Categories

Resources