Linq Include Extra Column in GroupBy Selection - c#

I have a "ReactionSimple" column that I'd like to include in the GroupBy selection but when I include it in the Group By it throws off the returned row count in a big way. Is there a way to include the commented out column in the final grouped selection without throwing off the result count. I'm a LINQ noob.
var reactivityResults = new List<ReactivityResultViewModel>();
var reactivityResults2 = new List<ReactivityResultViewModel>();
var classifications = GetMaterialClassifications(test.TestType);
var antigens = _db.Antigens.ToList();
if (test.ResultSets.Any())
{
var testResult = test.ResultSets.FirstOrDefault();
var dateReported = testResult.DateReported;
var details = testResult.ResultSetDetails.ToList();
if (details.Any())
{
reactivityResults = (from d in details
join a in _db.Antigens on d.AntigenId equals a.AntigenId
join ma in _db.MaterialAntigens on a.AntigenId equals ma.AntigenId
join md in _db.MaterialDefs on ma.MaterialDefId equals md.MaterialDefId
join c in classifications on md.MaterialId equals c.MaterialId
select new ReactivityResultViewModel
{
MaterialId = c.MaterialId,
MaterialName = c.MaterialName,
IsActive = md.IsActive,
ReactionSimple = (ReactionTypeEnum)d.ReactionSimple,
TestId = test.TestId,
AccessionId = test.AccessionId,
PatientFirstName = test.Patient.Party.NameFirst,
PatientLastName = test.Patient.Party.NameLast,
TestType = (TestTypeNoFlagsEnum)test.TestType,
DateReported = dateReported,
ManufacturerId = c.ManufacturerId,
ManufacturerName = c.ManufacturerName
})
.OrderBy(x => x.MaterialName)
.ToList();
var sreactivityResults2 = reactivityResults
.GroupBy(x => new {
x.MaterialId, x.AccessionId, x.DateReported,
x.IsActive, x.ManufacturerId, x.ManufacturerName,
x.MaterialName, x.PatientFirstName, x.PatientLastName,
x.TestId, x.TestType,
//x.ReactionSimple
})
.Select(x => new ReactivityResultViewModel
{
MaterialId = x.Key.MaterialId,
MaterialName = x.Key.MaterialName,
IsActive = x.Key.IsActive,
//ReactionSimple = x.Key.ReactionSimple,
TestId = test.TestId,
AccessionId = test.AccessionId,
PatientFirstName = test.Patient.Party.NameFirst,
PatientLastName = test.Patient.Party.NameLast,
TestType = (TestTypeNoFlagsEnum)test.TestType,
DateReported = dateReported,
ManufacturerId = x.Key.ManufacturerId,
ManufacturerName = x.Key.ManufacturerName
})
.ToList();
var sd2 = sreactivityResults2.ToList();
}
return reactivityResults;

Related

Execute query using LINQ or EF to fetch records from multiple tables

I've been searching for a while now. But all the solutions seems to be different than what I expect.
So this is my query in SQL:-
Select * from
(
select Name,Description Descr from CourseTbl
union all
select MainDesc Name,MainDesc Descr from CoursedescTbl
union all
select SubHeading Name,SubDesc Descr from CourseSubDesc
union all
select Name,Descr as Descr from InternTbl
)A where A.Name like '%D%' or A.Descr like '%D%'
I want to execute the above query using LINQ or EF. and return the list in Json format. So I tried many failed attempts and this is one of them:-
public JsonResult SearchDetail()
{
string SearchKey = Request.Form["SearchName"].ToString();
IEnumerable<SearchList> QueryResult;
using (EBContext db = new EBContext())
{
try
{
QueryResult =
(from x in db.Courses
select new { A = x.Name, B = x.Description })
.Concat(from y in db.CourseDesc
select new { A = y.MainHeading, B = y.MainDesc })
.Concat(from z in db.CourseSubDesc
select new { A = z.SubDesc, B = z.SubHeading })
.Concat(from w in db.Interns
select new { A = w.Name, B = w.Descr })
.ToList();
}
catch (Exception ex)
{
return new JsonResult
{
Data = ex.Message,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
return new JsonResult
{
Data = QueryResult,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
And my SearchList Class is like this:-
public class SearchList
{
public string Name { get; set; }
public string Descr { get; set; }
}
I'm not able to put the where clause in linq query which will search in all table.
I'm getting error when I assign queryresult to my ef query. It says cannot cast to Innumerable.
Thanks in Advance.
Could you explain more on the error you are getting?
Also, have you tried using .Union() in linq?
QueryResult = db.Courses.Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList(); //this isn't necessary
Edit: There are two ways to input where clause, either with each search, or at the end:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
.ToList();
Or:
QueryResult = db.Courses.Where(x=>x.Name == "Name").Select(x=> new { A = x.Name, B= x.Description})
.Union(db.CourseDesc.Where(y=>y.MainHeading == "Name").Select(y=> new {A = y.MainHeading, B = y.MainDesc })
.Union( //so on
//Where can go either before or after .ToList
.Where(item=>item.A == "Name")
.ToList();
You did not say what error/exception you are getting. But your QueryResult is of type IEnumerable<SearchList> and you appear to be assigning it an enumerable of anonymous type { A, B }.
Try this:
QueryResult = (from x in db.Courses
select new SearchList { Name = x.Name, Descr = x.Description })
.Concat(...)
.ToList();
Or
QueryResult = db.Courses.Select(x => new SearchList
{ Name = x.Name, Descr = x.Description})
.Concat(...)
.ToList();
UPDATE
Your #2 issue will be fixed if you changed your select to new up a SearchList as I did above, instead of new-ing an anonymous type.
As for your issue #1, you should insert the Where() before your Select():
result1 = db.Courses
.Where(x => x.Name.Contains('D') || x.Description.Contains('D'))
.Select(x => new SearchList { Name = x.Name, Descr = x.Description});
result2 = db.CourseDesc
.Where(y => y.MainHeading.Contains('D') || y.MainDesc.Contains('D'))
.Select(y => new SearchList { Name = y.MainHeading, Descr = y.MainDesc});
result3 = db.CourseSubDesc
.Where(...)
.Select(...);
QueryResult = result1.Concat(result2).Concat(result3).ToList();
Doing Where() as part of the query on each table is important so you do not fetch all records from that table, unlike if you do the Where() after Concat(). Also note that Concat() may throw an ArgumentNullException.
Take the lists Separately and query and concat
check this example
List<string> a = new List<string>() { "a", "b", "c" };
List<string> b = new List<string>() { "ab", "bb", "cb" };
IEnumerable<SearchList> QueryResult =
a.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x })
.Concat(b.Where(x => x.Contains("a")).Select(x => new SearchList() { Name = x, Descr = x }));

C# - LINQ - Sum a field from other table

I need to join two tables (Movimientos and Cuentas), group by CuentasId and make a SUM of Movimientos.Monto
Movimientos has a CuentasId to join this, and I can get the data from Cuentas but can not get the Sum.
This is my best approach, any help will be preciated, I'm a little confused with the syntax. Thanks in advance and kind regards,
var cuentas = (from mov in _data.Movimientos
join ct in _data.Cuentas
on mov.CuentasId equals ct.CuentasId
where ct.IsDeleted == 0 && mov.IsDeleted == 0
group ct by new
{
CuentasId = ct.CuentasId,
Alias = ct.Alias,
Moneda = ct.Monedas.Nombre,
Signo = ct.Monedas.Signo,
Banco = ct.Bancos.Nombre
} into ctg
select new
{
Alias = ctg.Key.Alias,
Moneda = ctg.Key.Moneda,
Signo = ctg.Key.Signo,
Banco = ctg.Key.Banco,
Monto = ctg.Sum(mov.Monto)
}
).ToList();
You need to group the value you want to sum like this
group mov.Monto by new { ..... } into ctg
Then ctg will be a collection of mov.Monto values grouped by your list of properties of ct and you'd just call Sum on ctg in your select
Monto = ctg.Sum()
So your new query would be
var cuentas = (from mov in _data.Movimientos
join ct in _data.Cuentas
on mov.CuentasId equals ct.CuentasId
where ct.IsDeleted == 0 && mov.IsDeleted == 0
group mov.Monto by new
{
CuentasId = ct.CuentasId,
Alias = ct.Alias,
Moneda = ct.Monedas.Nombre,
Signo = ct.Monedas.Signo,
Banco = ct.Bancos.Nombre
} into ctg
select new
{
Alias = ctg.Key.Alias,
Moneda = ctg.Key.Moneda,
Signo = ctg.Key.Signo,
Banco = ctg.Key.Banco,
Monto = ctg.Sum()
}).ToList();
You could also try grouping by first and then just summing the items later:
var cuentas = (from mov in _data.Movimientos.Where(w => w.IsDeleted == 0).GroupBy(g => g.CuentasId)
join ct in _data.Cuentas.Where(w => w.IsDeleted == 0).GroupBy(g => new { CuentasId = g.CuentasId, Alias = g.Alias, Monedas = g.Monedas.Nombre, Signo = g.Monedas.Signo, Banco = g.Bancos.Nombre })
on mov.Key.CuentasId equals ct.Key.CuentasId
select new
{
Alias = ct.Key.Alias,
Moneda = ct.Key.Moneda,
Signo = ct.Key.Signo,
Banco = ct.Key.Banco,
Monto = mov.Sum(s => s.Monto)
}
).ToList();

Returning List value using linq C#

Actually I want to return the data from different lists based on Date. When i'm using this i'm getting data upto #Var result but i'm unnable to return the data. The issue with this is i'm getting error #return result. I want to return the data #return result. I'm using Linq C#. Can anyone help me out?
public List<CustomerWiseMonthlySalesReportDetails> GetAllCustomerWiseMonthlySalesReportCustomer()
{
var cbsalesreeport = (from cb in db.cashbilldescriptions
join c in db.cashbills on cb.CashbillId equals c.CashbillId
join p in db.products on cb.ProductId equals p.ProductId
select new
{
Productamount = cb.Productamount,
ProductName = p.ProductDescription,
CashbillDate = c.Date
}).AsEnumerable().Select(x => new ASZ.AmoghGases.Model.CustomerWiseMonthlySalesReportDetails
{
Productdescription = x.ProductName,
Alldates = x.CashbillDate,
TotalAmount = x.Productamount
}).ToList();
var invsalesreeport = (from inv in db.invoices
join invd in db.invoicedeliverychallans on inv.InvoiceId equals invd.InvoiceId
select new
{
Productamount = invd.Total,
ProductName = invd.Productdescription,
InvoiceDate = inv.Date
}).AsEnumerable().Select(x => new ASZ.AmoghGases.Model.CustomerWiseMonthlySalesReportDetails
{
Productdescription = x.ProductName,
Alldates = x.InvoiceDate,
TotalAmount = x.Productamount
}).ToList();
var abc = cbsalesreeport.Union(invsalesreeport).ToList();
var result = (from i in abc
group i by new { Date = i.Alldates.ToString("MMM"), Product = i.Productdescription } into grp
select new { Month = grp.Key, Total = grp.Sum(i => i.TotalAmount) });
**return result;**
}
You can either convert your result to a List before returning it using return result.ToList() or make your method return an IEnumerable<CustomerWiseMonthlySalesReportDetails> instead of List.
As your result is an enumeration of anonymous types you have to convert them to your CustomerWiseMonthlySalesReportDetails-type first:
select new CustomerWiseMonthlySalesReportDetails{ Month = grp.Key, Total = grp.Sum(i => i.TotalAmount) });
Assuming your type has exactly the members returned by the select.
EDIT: So your code should look like this:
var result = (from i in abc
group i by new { Date = i.Alldates.ToString("MMM"), Product = i.Productdescription } into grp
select new CustomerWiseMonthlySalesReportDetails{ Month = grp.Key, Total = grp.Sum(i => i.TotalAmount) });
return result.ToList();
You can assume Alldates property if is date of one of groups that month of date is in right place:
var result = (from i in abc
group i by new { Date = i.Alldates.ToString("MMM"), Product = i.Productdescription }
into grp
select new CustomerWiseMonthlySalesReportDetails{
Productdescription = grp.Key.Product,
TotalAmount = grp.Sum(i => i.TotalAmount),
Alldates =grp.First(i=>i.Alldates ) })
.ToList();

How to debug query in c# program?

I want to write query more efficient.
I do not want before the end of the query, the list of data to extract.
var UserTimeLineNews = (from l in _newsService.NewsQuery()
where l.UserId == UserId && l.IsActive == true
orderby l.CreateDate descending
select new UserTimeLine
{
EventDate = l.CreateDate,
CreateDate = l.CreateDate,
NewsId = l.NewsId,
TimeLineType = TimeLineType.CreateNews,
Title = l.Title,
Abstract = l.NewsAbstract,
CommentCount = l.CommentCount,
LikeCount = l.LikeCount,
ViewsCount = l.ViewsCount,
Storyteller = l.Storyteller
}).AsQueryable();//Take(NumberOfNews).ToList();
var UserTimeLineLikeNews = (from l in _likeNewsService.LikeNewsQueryable()
where l.UserId == UserId
orderby l.CreateDate descending
select new UserTimeLine
{
EventDate = l.CreateDate,
CreateDate = l.CreateDate,
NewsId = l.NewsId,
TimeLineType = TimeLineType.LikeNews,
Title = l.News.Title,
Abstract = l.News.NewsAbstract,
CommentCount = l.News.CommentCount,
LikeCount = l.News.LikeCount,
ViewsCount = l.News.ViewsCount,
Storyteller = l.News.Storyteller
}).AsQueryable();//Take(NumberOfNews).ToList();
var UserTimeLineComments = (from l in _commentService.CommentQueryable()
where l.UserId == UserId && l.IsActive == true
orderby l.CreateDate descending
select new UserTimeLine
{
EventDate = l.CreateDate,
CreateDate = l.CreateDate,
NewsId = l.NewsId,
TimeLineType = TimeLineType.Comment,
Title = l.News.Title,
Abstract = l.News.NewsAbstract,
CommentContent = l.Content,
CommentCount = l.News.CommentCount,
LikeCount = l.News.LikeCount,
ViewsCount = l.News.ViewsCount,
Storyteller = l.News.Storyteller
}).AsQueryable();//Take(NumberOfNews).ToList();
var item = (UserTimeLineNews
.Union(UserTimeLineLikeNews)
.Union(UserTimeLineComments))
.OrderByDescending(e => e.EventDate)
.Distinct()
.Take(NumberOfNews)
.ToList();
After running the following error appears
Error:
The type 'UserTimeLine' appears in two structurally incompatible initializations within a single LINQ to Entities query.
A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.
The first two queries don't initialize the CommentContent property. Add that to the initializer in the first two queries (or remove it in the last query) and the final query should work.

LINQ group by expression syntax

I've got a T-SQL query similar to this:
SELECT r_id, r_name, count(*)
FROM RoomBindings
GROUP BY r_id, r_name
I would like to do the same using LINQ. So far I got here:
var rooms = from roomBinding in DALManager.Context.RoomBindings
group roomBinding by roomBinding.R_ID into g
select new { ID = g.Key };
How can I extract the count(*) and r_name part?
Try this:
var rooms = from roomBinding in DALManager.Context.RoomBindings
group roomBinding by new
{
Id = roomBinding.R_ID,
Name = roomBinding.r_name
}
into g
select new
{
Id = g.Key.Id,
Name = g.Key.Name,
Count = g.Count()
};
Edit by Nick - Added method chain syntax for comparison
var rooms = roomBinding.GroupBy(g => new { Id = g.R_ID, Name = g.r_name })
.Select(g => new
{
Id = g.Key.Id,
Name = g.Key.Name,
Count = g.Count()
});

Categories