How to OrderBy nested Object value Linq - c#

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;
}

Related

Cannot implicity convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.IList<LM_WebApi.Controllers.Items>

Having problem on my web api "Cannot implicity convert type IQueryable<> to Generic.List". I'm getting the data from Entity Framework.
When I put ToList() it return this error: System.Collections.Generic.List' to 'System.Collections.Generic.IList<LM_WebApi.Controllers.Items>
public IList<Sales_Data> GetSalesData()
{
using (var db = new LM_ReportEntities())
{
var list = db.OE_Invoiced_BaseProducts.Where(x => x.Year == "2020" && x.Period == 1);
IList<Sales_Data> salesData = new List<Sales_Data>();
salesData.Add(new Sales_Data { Items = list.Select(x => x.Item_Number).ToList() });
salesData.Add(new Sales_Data { Periods = list.Select(x => x.Period) });
return salesData;
}
}
Here are my class:
public class Items
{
public string Item_No { get; set; }
}
public class Periods
{
public string Period { get; set; }
}
My model:
public class Sales_Data
{
public IList<Items> Items { get; set; }
public IList<Periods> Periods { get; set; }
}
I want to return the data from Items and Periods as List.
You have to do this in the following way:
var list = db.OE_Invoiced_BaseProducts.Where(x => x.Year == "2020" && x.Period == 1).ToList();
In the next step, populate the lists of Items and Periods types from list collection.
var ItemsList = new List<Items>();
var PeriodsList = new List<Periods>();
foreach (var i in list)
{
Items item = new Items() { Item_No = i.Item_Number };
Periods period = new Periods() { Period = i.Period };
ItemsList.Add(item);
PeriodsList.Add(period);
}
Finally, populate Sales_Data model by the above lists.
var salesData = new Sales_Data() { Items = ItemsList, Periods = PeriodsList };
change db.OE_Invoiced_BaseProducts.Where(x => x.Year == "2020" && x.Period == 1) to db.OE_Invoiced_BaseProducts.Where(x => x.Year == "2020" && x.Period == 1).ToList()
Edit:
var list = db.OE_Invoiced_BaseProducts.Where(x => x.Year == "2020" && x.Period == 1);
...
salesData.Add(new Sales_Data { Items = list.Select(x => new Items{Item_No = x.Item_Number}).ToList() });
salesData.Add(new Sales_Data { Periods = list.Select(x => new Periods{Periods = x.Period}).ToList() });
First of all, I think, you made a mistake in model, change it this way:
public class Sales_Data
{
public string Item_No { get; set; }
public string Period { get; set; }
}
And then change your method like this:
public IList<Sales_Data> GetSalesData()
{
using (var db = new LM_ReportEntities())
{
var list = db.OE_Invoiced_BaseProducts.Where(x => x.Year == "2020" && x.Period == 1).ToList();
return (from baseProduct in db.OE_Invoiced_BaseProducts
where baseProduct.Year = "2020"
&& baseProduct.Period == 1
select new Sales_Data()
{
Item_No = baseProduct.Item_Number,
Period = baseProduct.Period
}).ToList();
}
}

Display count of task for each id

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.

Get result from list inside list

I have a structure like
class a
{
public IList<b> bs{ get; set; }
public class b
{
public string r{ get; set; }
public IList<sl> sls{ get; set; }
public class sl
{
public string sn{ get; set; }
public string st{ get; set; }
}
}
}
the query is like if sn == "abc" then get r
I have done
a aobj = new a();
var aa = aobj.bs.Where(c => c.sl != null).Select(c => c).ToList(); // here I get `r = "qwerty", sls will have data like sn = "qwerty0", st= "1" ; sn = "asdf" , st="2"; sn = "zxc" st = "abc"; sn="me" , st = "abc"
var bb = aa.where(c => c.sl.Select(dr => dr.st.ToLower().Contains("abc"))); // I 'm here checking that `sn` contain abc or not
var cc = bb.Select(c => c.r).ToList(); // result
my expected output of query is "zxc", "me"
but I am getting all the list not only contains abc.. can anyone suggest me what should I do? I am partitioning this query to debug.
Thank you
You'll need to use the Any operator to check if an enumerable collection has an item that meets a criteria.
You can't use Select as that only projects an item, it isn't returning an predicate and as such has no function in a where clause.
Here is your (fixed for syntax errors) changed code:
var aa = aobj.bs.Where(c => c.sls != null).Select(c => c).ToList();
// use Any here
var bb = aa.Where(c => c.sls.Any(dr => dr.sn.ToLower().Contains("abc")));
var cc = bb.Select(c => c.r).ToList();
And here is the test set I used:
a aobj = new a();
aobj.bs = new List<b>();
aobj.bs.Add(new b {
r ="bar",
sls = new List<sl>{
new sl { sn="tets"},
new sl { sn="no"}
}
});
aobj.bs.Add(new b {
r ="foo",
sls = new List<sl>{
new sl { sn="no"},
new sl { sn="abc"}
}
});
aobj.bs.Add(new b {
r ="fubar",
sls = new List<sl>{
new sl { sn="no"},
new sl { sn="abc"}
}
});
This will output:
foo
fubar
If you combine all operators together you'll get:
var merged = aobj
.bs
.Where(c => c.sls != null
&& c.sls.Any(dr => dr.sn.ToLower().Contains("abc")))
.Select(c => c.r);
I think you can use a code like this:
var cc = a.bs
.Where(w => w.sls?.Any(s => s.st?.ToLower().Contains("abc") ?? false) ?? false)
.Select(c => c.r);

Return an new object from join using EntityFramework

I am a little bit stuck here.
I got a Database with tables for projects and versions of these projects:
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public List<ProjectVersion> Versions { get; set; } = new List<ProjectVersion>();
public Project() { }
}
and
public class ProjectVersion
{
public int Id { get; set; }
public string Version { get; set; }
public string Checksum { get; set; }
public string Description { get; set; }
public ICollection<EntryPoint> EntryPoints { get; set; } = new List<EntryPoint>();
public ICollection<System> Systems { get; set; } = new List<System>();
public ProjectVersion() { }
}
now I want to get a specific version of a project and some detailed information
public static Project GetVersionByProjectId( int projectId, string version )
{
using ( var ctx = new DatabaseContext() )
{
var query =
ctx.Projects
.Where(p => p.Id.Equals(projectId))
.Join(
ctx.Versions.Where( v => v.Version.Equals( version )),
p => p.Id,
v => v.ProjectId,
(p, v) => new Project
{
Name = p.Name,
Type = p.Type,
Id = p.Id,
Versions = new List<ProjectVersion>
{
new ProjectVersion
{
Checksum = v.Checksum,
Description = v.Description,
Version = v.Version ,
EntryPoints = new List<EntryPoint>(v.EntryPoints),
Systems = new List<System>(v.Systems)
}
}
}
)
.Select(x => x);
var result = query.ToList();
return result[0];
}
}
if I remove the whole
Versions = new List<ProjectVersion>
it works and I get the Project but not the Version. When I tried the LINQ in LINQPad I got following error:
Cannot create a query result of type 'System.Collections.Generic.List`1[UserQuery+ProjectVersion]'.
How can I get the Project with the requested Version?
UPDATE
thanks to the ideas of #RomanoZumbé and #Maritim I could solve it. Problem was different classes of the models.
using ( var ctx = new DatabaseContext() )
{
var query =
ctx.Projects
.Include(p => p.Versions)
.Where(p => p.Id.Equals(projectId))
.Select( p =>
new Project()
{
Id = p.Id,
Name = p.Name,
Type = p.Type,
Versions =
p.Versions
.Where( v => v.Version.Equals(version))
.Select( v =>
new ProjectVersion()
{
Checksum = v.Checksum,
Description = v.Description,
EntryPoints =
v.EntryPoints
.Select( e => new EntryPoint()
{
Call = e.Call,
Step = e.Step
})
.ToList()
})
.ToList()
})
.Select(x => x);
var result = query.ToList();
return result[0];
}
I don't know if I understood it correctly, and this is from top of my mind, but I think it would be easier if you used the Include(...) statement. And since you already included the project 'Versions' (which is equivalent to a JOIN statement in the database), you can do something like:
var query =
ctx.Projects
.Include(p => p.Versions)
.Where(p => p.Id.Equals(projectId))
.Select(
new Project
{
Name = p.Name,
Type = p.Type,
Id = p.Id,
Versions = p.Versions.Where(v => v.Version.Equals(version))
});
return query.FirstOrDefault();
I'm not entirely sure wether this is what you want to achieve, but maybe it helps.
var res = (from p in ctx.Projects
let v = ctx.Versions.FirstOrDefault(x => p.Versions.Any(v => v.Id == x.Id))
where p.Id == projectId
select new Project
{
Name = p.Name,
Type = p.Type,
Id = p.Id,
Versions = new List<ProjectVersion>()
{
new ProjectVersion
{
Checksum = v.Checksum,
Description = v.Description,
Version = v.Version ,
EntryPoints = new List<EntryPoint>(v.EntryPoints),
Systems = new List<System>(v.Systems)
}
}
});
return res.FirstOrDefault()

Join (Include) Between Model and AspNetUsers

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

Categories