I have page where i display list of tasks (with Jquery DataTable) and i want display Employee name with count of thire tasks. for example:
Smith (2) | John (1) | Thomas (1)
Tables:
AssignName:
Tasks (AssignId as ForeignKey):
Here what i did :
Here i get List of tasks and select some properties:
var Taskslist = db.Tasks.Select(g => new ServicetasksVM.ItemGroup
{
OpgaveServicesId = g.Id,
Opgaver = g.Opgaver,
Opgaveid = g.Id,
Opretteaf = g.Opretteaf,
OpretteDato = g.OpretteDato,
}).AsEnumerable();
Her iterating over the results to get count each id:
foreach (var item in result)
{
var AssignCount = db.AssignName.Where(c => c.Id == item.Assingid)
.GroupBy(x => x.Name)
.Select(b => new ServicetasksVM.ItemGroup { Assingid = b.Count(), EmployeeNames= b.Key });
}
Put all code together (for simplicity i remove unneeded code):
public JsonResult ListofTasks() {
var Taskslist = db.Tasks.Select(g => new ServicetasksVM.ItemGroup
{
OpgaveServicesId = g.Id,
Opgaver = g.Opgaver,
Opgaveid = g.Id,
Opretteaf = g.Opretteaf,
OpretteDato = g.OpretteDato,
}).AsEnumerable();
var result = Taskslist.Skip(start).Take(length).ToList();
foreach (var item in result)
{
var AssignCount = db.AssignName.Where(c => c.Id == item.Assingid)
.GroupBy(x => x.Name)
.Select(b => new ServicetasksVM.ItemGroup { Assingid = b.Count(), EmployeeNames= b.Key });
}
JsonResult json = Json(new { data = result, draw = Request["draw"], recordsTotal = totalrows, recordsFiltered = totalrowsefterfiltering }, JsonRequestBehavior.AllowGet);
json.MaxJsonLength = int.MaxValue;
return json;
ViewModel:
public List<ItemGroup> ItemGroups { get; set; }
public class ItemGroup
{
public ItemGroup()
{
}
public int OpgaveServicesId { get; set; }
public string Opgaver { get; set; }
public string Opretteaf { get; set; }
public DateTime? OpretteDato { get; set; }
public int Opgaveid { get; set; }
public int OpgaveSmartid { get; set; }
public string Opgavestatus { get; set; }
public int? Assingid { get; set; }
public string EmployeeNames { get; set; }
}
In the end when I check the results both Assingid and EmployeeNames are null. Can anyone please help me :)
Scope of AssignCount variable is limited to foreach loop, that is the reason you are getting Assingid and EmployeeNames as a null at the end of program.
To fix this issue, store each AssignCount to the list, so that you can access all counts out of foreach loop
...
//Define list of List of ItemGroup, as AssignCount is of type List<ItemGroup>
List<List<ServicetasksVM.ItemGroup>> itemGroups = new List<List<ServicetasksVM.ItemGroup>>();
foreach (var item in result)
{
var AssignCount = db.AssignName.Where(c => c.Id == item.Assingid)
.GroupBy(x => x.Name)
.Select(b => new ServicetasksVM.ItemGroup { Assingid = b.Count(), EmployeeNames= b.Key })
.ToList(); //Convert To List
itemGroups.Add(AssignCount); //Add each `AssignCount` to itemGroups
}
//Now list of AssignCount(s) is(are) accessible outside foreach loop
...
Your for loop is doing the counting and assigning it to the variable AssignCount which only exists in the scope of the for loop. You need to capture that result in a variable that is outside the scope of the loop to pass that along to your view.
Something like:
var itemGroups = new List<ItemGroup>();
foreach (var item in result)
{
var AssignCount = db.AssignName.Where(c => c.Id == item.Assingid)
.GroupBy(x => x.Name)
.Select(b => new ServicetasksVM.ItemGroup { Assingid = b.Count(), EmployeeNames= b.Key });
itemGroups.Add(AssignCount);
}
variable AssignCount is local in the foreach loop. better create collection outside of the loop and keep on adding to it inside the loop.
Related
I have the below two classes:
public class FirstInner
{
public int Id { get; set; }
public string Type { get; set; }
public string RoleId { get; set; }
}
public class SecondInner
{
public int Id { get; set; }
public string Type { get; set; }
}
Again, there are lists of those types inside the below two classes:
public class FirstOuter
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public List<FirstInner> Inners { get; set; }
}
public class SecondOuter
{
public int Id { get; set; }
public string Name { get; set; }
public List<SecondInner> Inners { get; set; }
}
Now, I have list of FirstOuter and SecondOuter. I need to check if FirstOuter list is a subset of SecondOuter list.
Please note:
The names of the classes cannot be changed as they are from different systems.
Some additional properties are present in FirstOuter but not in SecondOuter. When comparing subset, we can ignore their presence in SecondOuter.
No.2 is true for FirstInner and SecondInner as well.
List items can be in any order---FirstOuterList[1] could be found in SecondOuterList[3], based on Id, but inside that again need to compare that FirstOuterList[1].FirstInner[3], could be found in SecondOuterList[3].SecondInner[2], based on Id.
I tried Intersect, but that is failing as the property names are mismatching. Another solution I have is doing the crude for each iteration, which I want to avoid.
Should I convert the SecondOuter list to FirstOuter list, ignoring the additional properties?
Basically, here is a test data:
var firstInnerList = new List<FirstInner>();
firstInnerList.Add(new FirstInner
{
Id = 1,
Type = "xx",
RoleId = "5"
});
var secondInnerList = new List<SecondInner>();
secondInner.Add(new SecondInner
{
Id = 1,
Type = "xx"
});
var firstOuter = new FirstOuter
{
Id = 1,
Name = "John",
Title = "Cena",
Inners = firstInnerList
}
var secondOuter = new SecondOuter
{
Id = 1,
Name = "John",
Inners = secondInnerList,
}
var firstOuterList = new List<FirstOuter> { firstOuter };
var secondOuterList = new List<SecondOuter> { secondOuter };
Need to check if firstOuterList is part of secondOuterList (ignoring the additional properties).
So the foreach way that I have is:
foreach (var item in firstOuterList)
{
var secondItem = secondOuterList.Find(so => so.Id == item.Id);
//if secondItem is null->throw exception
if (item.Name == secondItem.Name)
{
foreach (var firstInnerItem in item.Inners)
{
var secondInnerItem = secondItem.Inners.Find(sI => sI.Id == firstInnerItem.Id);
//if secondInnerItem is null,throw exception
if (firstInnerItem.Type != secondInnerItem.Type)
{
//throw exception
}
}
}
else
{
//throw exception
}
}
//move with normal flow
Please let me know if there is any better approach.
First, do the join of firstOuterList and secondOuterList
bool isSubset = false;
var firstOuterList = new List<FirstOuter> { firstOuter };
var secondOuterList = new List<SecondOuter> { secondOuter };
var jointOuterList = firstOuterList.Join(
secondOuterList,
p => new { p.Id, p.Name },
m => new { m.Id, m.Name },
(p, m) => new { FOuterList = p, SOuterList = m }
);
if(jointOuterList.Count != firstOuterList.Count)
{
isSubset = false;
return;
}
foreach(var item in jointOuterList)
{
var jointInnerList = item.firstInnerList.Join(
item.firstInnerList,
p => new { p.Id, p.Type },
m => new { m.Id, m.type },
(p, m) => p.Id
);
if(jointInnerList.Count != item.firstInnerList.Count)
{
isSubset = false;
return;
}
}
Note: I am assuming Id is unique in its outer lists. It means there will not be multiple entries with same id in a list. If no, then we need to use group by in above query
I think to break the question down..
We have two sets of Ids, the Inners and the Outers.
We have two instances of those sets, the Firsts and the Seconds.
We want Second's inner Ids to be a subset of First's inner Ids.
We want Second's outer Ids to be a subset of First's outer Ids.
If that's the case, these are a couple of working test cases:
[TestMethod]
public void ICanSeeWhenInnerAndOuterCollectionsAreSubsets()
{
HashSet<int> firstInnerIds = new HashSet<int>(GetFirstOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> firstOuterIds = new HashSet<int>(GetFirstOuterList().Select(outer => outer.Id).Distinct());
HashSet<int> secondInnerIds = new HashSet<int>(GetSecondOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> secondOuterIds = new HashSet<int>(GetSecondOuterList().Select(outer => outer.Id).Distinct());
bool isInnerSubset = secondInnerIds.IsSubsetOf(firstInnerIds);
bool isOuterSubset = secondOuterIds.IsSubsetOf(firstOuterIds);
Assert.IsTrue(isInnerSubset);
Assert.IsTrue(isOuterSubset);
}
[TestMethod]
public void ICanSeeWhenInnerAndOuterCollectionsAreNotSubsets()
{
HashSet<int> firstInnerIds = new HashSet<int>(GetFirstOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> firstOuterIds = new HashSet<int>(GetFirstOuterList().Select(outer => outer.Id).Distinct());
HashSet<int> secondInnerIds = new HashSet<int>(GetSecondOuterList().SelectMany(outer => outer.Inners.Select(inner => inner.Id)).Distinct());
HashSet<int> secondOuterIds = new HashSet<int>(GetSecondOuterList().Select(outer => outer.Id).Distinct());
firstInnerIds.Clear();
firstInnerIds.Add(5);
firstOuterIds.Clear();
firstOuterIds.Add(5);
bool isInnerSubset = secondInnerIds.IsSubsetOf(firstInnerIds);
bool isOuterSubset = secondOuterIds.IsSubsetOf(firstOuterIds);
Assert.IsFalse(isInnerSubset);
Assert.IsFalse(isOuterSubset);
}
private List<FirstOuter> GetFirstOuterList() { ... }
private List<SecondOuter> GetSecondOuterList() { ... }
Object
namespace Example
{
public class ContractorAddValue
{
public Member Member { get; set; }
public List<Addresses> Addresses { get; set; }
public ICommand AddAddress { get; set; }
}
public class Addresses
{
public MemberAddress MemberAddress { get; set; }
public ICommand EditAddress { get; set; }
}
}
Query
public ObservableCollection<ContractorAddValue> GetContractorsOrderByCity()
{
var allContractors = (from c in db.Member where c.IsContrator == true select c).ToList();
//var allContractors2 = db.Member .Include(c => c.MemberAddress).SelectMany(c => c.MemberAddress).OrderBy(c => c.City).Select(c => c.Member ).ToList();
//var allContractors = (from c in db.Member where c.IsContrator == true select c).OrderBy(c => c.MemberAddress.OrderBy(x => x.City)).ToList(); <= dosent work
var listContractorAddValue = new ObservableCollection<ContractorAddValue>();
foreach (var i in allContractors)
{
var adressList = db.MemberAddress.Where(x => x.MemberId == i.MemberId).OrderBy(x => x.City).ToList();
ContractorAddValue contractorAddValue = new ContractorAddValue();
contractorAddValue.Member = i;
contractorAddValue.AddAddress = new BaseCommand(() => ContractorsViewModel.SendAddress(i.MemberId ));
contractorAddValue.Addresses = new List<Addresses>();
foreach (var a in adressList)
{
Addresses memberAdress = new Addresses();
memberAdress.MemberAddress = a;
memberAdress.EditAddress = new BaseCommand(() => ContractorsViewModel.SendEditAddress(a.MemberAddressId , i.MemberId ));
contractorAddValue.Addresses.Add(memberAdress);
}
listContractorAddValue.Add(contractorAddValue);
}
return listContractorAddValue;
}
allContractors2 - the order by works, but I retrieve repeating Members. In this approach I tried to use .Distinct() after Select(c => c.Member) but it doesn't work (the whole query stops working).
My goal is to make an order by MemberAddress.City
Thanks in advance!
I think that this code will work but you need to redefine the Equals method of the ContractorAddValue class.
I added one if statement when you want to add contractorAddValue to the list. First you need to check if your list contains that object. If not you add the object to the list. If yes you need to find that object and merge its addresses list with addresses list from the object you want to add.
public ObservableCollection<ContractorAddValue> GetContractorsOrderByCity()
{
var allContractors = (from c in db.Member where c.IsContrator == true select c).ToList();
//var allContractors2 = db.Member .Include(c => c.MemberAddress).SelectMany(c => c.MemberAddress).OrderBy(c => c.City).Select(c => c.Member ).ToList();
//var allContractors = (from c in db.Member where c.IsContrator == true select c).OrderBy(c => c.MemberAddress.OrderBy(x => x.City)).ToList(); <= dosent work
var listContractorAddValue = new ObservableCollection<ContractorAddValue>();
foreach (var i in allContractors)
{
var adressList = db.MemberAddress.Where(x => x.MemberId == i.MemberId).OrderBy(x => x.City).ToList();
ContractorAddValue contractorAddValue = new ContractorAddValue();
contractorAddValue.Member = i;
contractorAddValue.AddAddress = new BaseCommand(() => ContractorsViewModel.SendAddress(i.MemberId ));
contractorAddValue.Addresses = new List<Addresses>();
foreach (var a in adressList)
{
Addresses memberAdress = new Addresses();
memberAdress.MemberAddress = a;
memberAdress.EditAddress = new BaseCommand(() => ContractorsViewModel.SendEditAddress(a.MemberAddressId , i.MemberId ));
contractorAddValue.Addresses.Add(memberAdress);
}
if(!listContractorAddValue.Contains(contractorAddValue)){
listContractorAddValue.Add(contractorAddValue);
} else {
var contAddValue = listContractorAddValue.First(l => l.Equals( contractorAddValue));
contAddValue.Addresses.AddRange(contractorAddValue.Addresses);
}
}
return listContractorAddValue;
}
Consider objModels is object of ChildModel class
public class ChildModel
{
public string Title { get; set; }
public long Id { get; set; }
}
It has some data like:
title,id: a,1 b,1 a,1
Two of these data are same, and after distinct it could be like: a,1 b,1
Question is how could I distinct it on c#
List<ChildModel> obj= objModels.ToList();
Also these aren't help
objModels.Distinct();
obj.Distinct();
You could use a library named MoreLINQ
This is the query you could use with MoreLINQ to find elements that are distinct by multiple properties:
var query = objModels.DistinctBy(p => new { p.Id, p.Title});
try this:
var answer= obj.DistinctBy(p => new { p.Id , p.Title });
and check this link for other way
I would do the following:
namespace ConsoleApplication7
{
class Program
{
static void Main()
{
List<ChildModel> list = new List<ChildModel>();
list.Add(new ChildModel { Title = "a", Id = 1 });
list.Add(new ChildModel { Title = "b", Id = 1 });
list.Add(new ChildModel { Title = "a", Id = 1 });
var x = list.Distinct(new ChildModelComparer()).ToList();
var y = x; //This has only got two child items.
}
}
class ChildModelComparer : IEqualityComparer<ChildModel>
{
public bool Equals(ChildModel x, ChildModel y)
{
return x.Id.Equals(y.Id) && x.Title.Equals(y.Title);
}
public int GetHashCode(ChildModel obj)
{
if (string.IsNullOrEmpty(obj.Title) && obj.Id == 0)
{
return 0;
}
return $"{obj.Id}{obj.Title}".GetHashCode();
}
}
public class ChildModel
{
public string Title { get; set; }
public long Id { get; set; }
}
}
you can use .GroupBy:
var result= obj
.GroupBy(p => p.Title)
.Select(g => g.First()) // choose which one
.ToList();
edit: if you want to GroupBy more than one Property you can just change p.Title to new {p.Title, p.Id} like so
var result= obj
.GroupBy(p => new {p.Title, p.Id})
.Select(g => g.First()) // choose which one
.ToList();
Several time, i need to get the name of user in AplicationUsers (aspnetusers). Like in Chamado model (table) i have a column Id_Agente (user). With a simple List, i will get something like:
"3q0aju9-9ijuso-9sodkci..."
public class Chamado
{
public int Id { get; set; }
public DateTime Abertura { get; set; }
public string Titulo { get; set; }
public string Descricao { get; set; }
public string Id_Agente { get; set; }
[NotMapped]
public String NomeAgente { get; set; }
}
To work around, I created a NotMapped field and filled it with a foreach:
using (IdentityContext id2 = new IdentityContext())
{
foreach (var item in historicos)
{
item.NomeAgente = id2.Users
.Where(u => u.Id == item.Id_Agente)
.Select(u => u.Nome).FirstOrDefault();
}
}
But now I need to group Chamados by Agente, and it's becoming more and more harder, to work around. I tried to make another notMapped on chamados model named Qtde, make a list and extract from that list but returned a error:
public List<PainelChamados> ListarOrdem()
{
using (SistemaContext db = new SistemaContext())
{
var chamados = db.Chamado
.Where(c => c.Situacao != Chamado.Esituacao.Concluido)
.GroupBy(c => c.Id_Agente)
.Select(c => new Chamado { Id_Agente = c.Key, Qtde = c.Count() });
using (IdentityContext id2 = new IdentityContext())
{
foreach (var item in chamados)
{
item.NomeAgente = id2.Users
.Where(u => u.Id == item.Id_Agente)
.Select(u => u.Nome).FirstOrDefault();
}
}
var query = chamados
.Select(c => new PainelChamados
{
Agente = c.NomeAgente,
Qtde = c.Qtde
});
return query.ToList();
}
}
Last, but not least, how could I just Include aspnetusers table like another regular table:
var query = db.Suporte_Projeto
.Include(l => l.Licenciado)
.Include(c => c.Condominio)
.Include(pr => pr.ProjetoProduto)
.Include(p => p.ProjetoAcesso);
Chart Data
Error
I did another work around! It's seems to be a good option while i cant join aspnetusers to my models table:
public List<PainelChamados> ListarOrdem()
{
using (SistemaContext db = new SistemaContext())
{
var query = db.Chamado
.Where(c => (c.Situacao != Chamado.Esituacao.Concluido && c.Id_Agente != null))
.GroupBy(e => new { e.Id_Agente})
.Select(lg => new PainelChamados
{
CodAgente = lg.Key.Id_Agente,
Qtde = lg.Count()
});
UsuarioData ud = new UsuarioData();
List<PainelChamados> Lista = new List<PainelChamados>();
foreach (var item in query)
{
Lista.Add(new PainelChamados
{
CodAgente = item.CodAgente,
Agente = item.CodAgente == null ? string.Empty : ud.GetAgenteId(item.CodAgente),
Qtde = item.Qtde
});
}
return Lista;
}
}
What do you think, is it the best way to work around? I could return the list i desired.
Chart With Agente Names
from x in myCollection
group x by x.Id into y
select new {
Id = y.Key,
Quantity = y.Sum(x => x.Quantity)
};
How would you write the above as a lambda expression? I'm stuck on the group into part.
Query continuations (select...into and group...into, but not join...into) are equivalent to just splitting up the query expression. So I like to think of your example as:
var tmp = from x in myCollection
group x by x.Id;
var result = from y in tmp
select new {
Id = y.Key,
Quantity = y.Sum(x => x.Quantity)
};
Change those into dot notation:
var tmp = myCollection.GroupBy(x => x.Id);
var result = tmp.Select(y => new {
Id = y.Key,
Quantity = y.Sum(x => x.Quantity)
});
Then you could combine them back:
var tmp = myCollection.GroupBy(x => x.Id)
.Select(y => new {
Id = y.Key,
Quantity = y.Sum(x => x.Quantity)
});
Once you work out what the C# compiler does with query expressions, the rest is relatively straightforward :)
myCollection
.GroupBy(x => x.Id)
.Select(x =>
new
{
Id = x.Key,
Quantity = x.Sum(y => x.Quantity
});
myCollection.GroupBy(x => x.Id)
.Select(y => new {
Id = y.Key,
Quantity = y.Sum(x => x.Quantity)
});
var mostFrequent =
lstIn.Where(i => !string.IsNullOrEmpty(i))
.GroupBy(s => s)
.OrderByDescending(g => g.Count())
.Select(s => s.Key)
.FirstOrDefault();
So, for most of the answers here, everyone seems to be dealing with getting a simple object of Id made from count of the group, and the Key itself which is group.Key.
Although thats probably the main useage of this. Didn't really satisfy my needs.
For my own case, I basically wanted to group by some object property, then fetch a specific object from that group. Here's a sample code.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var response = new List<ResponseClass>();
var listOfStudents = new List<Student>();
// Insert some objects into listOfStudents object.
listOfStudents.GroupBy(g => g.Class).ToList()
.ForEach(g => response.Add(g.OrderByDescending(s => s.CreatedOn).Select(a =>
new ResponseClass
{
SName = a.StudentName,
SAge = a.Age,
SClass = a.Class,
SCreatedOn = a.CreatedOn,
RandomProperty = Guid.NewGuid().ToString()
})
.First()));
Console.WriteLine("This compiles and should work just fine");
}
class Student
{
public string StudentName { get; set; }
public int Age { get; set; }
public string Class { get; set; }
public DateTime CreatedOn { get; set; }
}
class ResponseClass
{
public string SName { get; set; }
public int SAge { get; set; }
public string SClass { get; set; }
public DateTime SCreatedOn { get; set; }
public string RandomProperty { get; set; }
}
}
If you would rather use a foreach loop (I prefer lambda as I find it easier to read), but if you do, you could do it like so.
foreach (IGrouping<string, Student> groupedStudents in listOfStudents.GroupBy(g => g.Class))
{
response.Add(groupedStudents.OrderByDescending(x => x.CreatedOn).Select(a =>
new ResponseClass
{
SName = a.StudentName,
SAge = a.Age,
SClass = a.Class,
SCreatedOn = a.CreatedOn,
RandomProperty = Guid.NewGuid().ToString()
}).First());
}
Hope this helps someone. :)