Linq query with Average - c#

I have 3 tables:
tblCompany : Id, Name, Location
tblRating : Id, CompanyId, Rate
tblImages : Id, CompanyId, ImagePath
I have a class
public class Company
{
public string Id { get; set; }
public string CompanyName { get; set; }
public string Location { get; set; }
public string AverageRate { get; set; }
public List<string> ImagePath { get; set; }
}
I want a LINQ query to produce a result to match the Company class.
I wrote this query but it does not work
List<Company> result = null;
using (DataContext dc = new DataContext())
{
result = (from a in dc.GetTable<tblCompany>()
join b in dc.GetTable<tblRating>()
on a.Id equals b.CompanyId
join c in dc.GetTable<tblImages>()
on a.Id equals c.CompanyId
select new SearchResult
{
CompanyName = a.Company,
Location = a.Location,
AverageRate = b.Rate.Average(),
ImagePath = c.ImagePath.ToList()
}).ToList<Company>();
}

Edited for whole Query:
(I've to say i'm sorry but i have no way of testing this query yet)
You can use the let clause instead of the joins:
var result = (from c in dc.GetTable<tblCompany>()
let r = (from re in dc.GetTable<tblRating>()
where re.CompanyId == c.Id && re.Rate != null
select re.Rate)
let i = (from im in dc.GetTable<tblImages>()
where im.CompanyId == c.Id
select im.ImagePath)
select new SearchResult
{
CompanyName = c.Name,
Location = c.Location,
AverageRate = r.Average(),
ImagePath = i.ToList()
}).ToList<Company>();

try this -
result = (from a in dc.GetTable<tblCompany>()
join b in dc.GetTable<tblRating>()
on a.Id equals b.CompanyId
join c in dc.GetTable<tblImages>()
on a.Id equals c.CompanyId
group new { b.Rate, c.ImagePath}
by new { a.Id, a.Location,a.Name} into groupList
select new Company
{
CompanyName = groupList.Key.Name,
Location = groupList.Key.Location,
AverageRate = groupList.Average(a=>a.Rate),
ImagePath = groupList.Select(i=>i.ImagePath).ToList()
}).ToList<Company>();

Related

How to Get Last Record Using LINQ - Entity Framework in SQLite

I need to translate the following SQLite query to LINQ in C#
SELECT sup.SupplierName, sup.SupplierID, pr.Price, max(pr.AddedDate)
FROM Suppliers sup
LEFT JOIN ItemsPrices pr
USING(SupplierID)
WHERE pr.ItemID = '22'
GROUP BY sup.SupplierName
I've searched about all web site and tried the following LINQ query and it does group like what I want but doesn't select latest date. I'm newbie in LINQ please help me
internal List<LatestPriceDbo> GetLatestPrice(int _itemid)
{
using (dbContext context = new dbContext())
{
var groupedPrice = from a in context.ItemsPrices
where a.ItemId == _itemid
orderby a.Id descending
group a by new { a.ItemId, a.SupplierId } into g
select new ItemsPrice
{
SupplierId = g.Key.SupplierId,
ItemId = g.Key.ItemId,
Price = g.FirstOrDefault().Price,
AddedDate = g.Max(s => s.AddedDate)
};
var result = (from c in context.Suppliers
from k in groupedPrice
where k.ItemId == _itemid && c.SupplierId == k.SupplierId
select new LatestPriceDbo
{
supid = c.SupplierId,
supname = c.SupplierName,
price = k.Price,
addeddate = k.AddedDate
}).ToList();
return result;
}
}
internal class LatestPriceDbo
{
public int supid { get; set; }
public string supname { get; set; }
public decimal price { get; set; }
public string addeddate { get; set; }
}
I am using Database-First.
You should be able to use a LINQ Join I have mocked up something which might point you in the correct direction:
Notes
use the join first to get the set you looking for
you can then do a nested select for the max based on supplierId.
from a in context.ItemsPrices
join s in context.Suppliers on a.SupplierId equals s.supplierId
where a.ItemId == _itemid
orderby a.Id descending
select new ItemsPrice
{
SupplierName = s.SupplierName
SupplierId = a.SupplierId,
ItemId = a.ItemId,
Price = a.FirstOrDefault().Price,
AddedDate = context.ItemsPrices.Where(x => x.SupplierId == a.SupplierId).Max(s => s.AddedDate)
};
I solved the problem owing to Kevin's suggestion. I did need to be more search on web to improve the code block of Kevin's comment and I did.
internal List<LatestPriceDbo> GetLatestPrice(int _itemid)
{
using (dbContext context = new dbContext())
{
var result = (from a in context.ItemsPrices
join s in context.Suppliers on a.SupplierId equals s.SupplierId
where a.ItemId == _itemid
orderby a.Id descending
group new { a, s } by new { a.SupplierId, a.ItemId } into grb
select new LatestPriceDbo
{
supname = grb.FirstOrDefault().s.SupplierName,
supid = grb.Key.SupplierId,
itemid = grb.Key.ItemId,
price = context.ItemsPrices
.Where(x => x.ItemId == grb.FirstOrDefault().a.ItemId)
.OrderByDescending(z => z.Id).Select(z => z.Price)
.FirstOrDefault(),
addeddate = context.ItemsPrices
.Where(x => x.SupplierId == grb.FirstOrDefault().a.SupplierId)
.Max(s => s.AddedDate)
}).ToList();
return result;
}
}
internal class LatestPriceDbo
{
public int itemid { get; set; }
public int supid { get; set; }
public string supname { get; set; }
public decimal price { get; set; }
public string addeddate { get; set; }
public int recordid { get; set; }
}

How to bind linq data into Model class

I have following query,
var userTree = (from user in users
join location in locations on user.FkHomeLocationId equals location.LocationId
join region in regions on location.RegionId equals region.LocationId
group region by new {
Regionid = region.LocationId,
location.LocationId
}
into grp
select new {
RegionName = regions.FirstOrDefault(s = >s.LocationId == grp.Key.Regionid).LocationName,
Branches = new {
BranchName = locations.FirstOrDefault(b = >b.RegionId == grp.Key.Regionid).LocationName,
Users = users.Where(u = >u.FkHomeLocationId == grp.Key.LocationId).Select(s = >new {
FullName = s.FirstName + " " + s.LastName
}).ToList()
}
}).ToList();
I want to bind the query result into model. how can I do this. I created following class model to achieve that,
public class TreeModel
{
public string RegionName { get; set; }
public Branch Branchs { get; set; }
}
public class Branch
{
public string BranchName { get; set; }
public List<User> Users { get; set; }
}
public class User
{
public string FirstName { get; set; }
}
Now need to bind above query data into this model class? Have any best way to do this without creating Branch and User classes? because my application have another classes with the same name of User and Branch and I feel some guilty to create separate classes like this for query data binding? I'm I correct?
Updated: I tried as follows,
var userTree = (from user in users
join location in locations on user.FkHomeLocationId equals location.LocationId
join region in regions on location.RegionId equals region.LocationId
group region by new {
Regionid = region.LocationId,
location.LocationId
}
into grp
select new Application.Alerts.Models.AlertUserTreeViewModel() {
RegionName = regions.FirstOrDefault(s = >s.LocationId == grp.Key.Regionid).LocationName,
Branchs = new Application.Alerts.Models.Branch() {
BranchName = locations.FirstOrDefault(b = >b.RegionId == grp.Key.Regionid).LocationName,
Users = new Application.Alerts.Models.User {
FirstName = users.Where(u = >u.FkHomeLocationId == grp.Key.LocationId).FirstOrDefault().FirstName
}
}
}).ToList();
But I'm getting compile error in this line,
Users = new Application.Alerts.Models.User {
FirstName = users.Where(u = >u.FkHomeLocationId == grp.Key.LocationId).FirstOrDefault().FirstName
}
as
Cannot implicitly convert type 'Alerts.Models.User' to 'System.Collections.Generic.List<Alerts.Models.User>'
just add extra FirstName property to your anonymous classes
var userTree =
....
select new {
RegionName = ...
Branches = new {
BranchName = ...,
Users = ....Select(s = >new {
FirstName=s.FirstName,
FullName = s.FirstName + " " + s.LastName
}).ToList()
}
after this you can create view model
var treeModel= userTree.Select( new TreeModel {
RegionName = userTree.RegionName
Branchs =userTree.Branches.Select(i=>
new Branch {
BranchName= i.BranchName,
Users= i.Users.Select(j=> new User{ FirstName=j.Firstname})
)});
if you need only fullname in your userTree you can convert back
userTree= userTree.Select( new TreeModel {
RegionName = userTree.RegionName
Branchs =userTree.Branches.Select(i=>
new Branch {
BranchName= i.BranchName,
Users= i.Users.Select( j=> new {j.FullName})
)});
UPDATE
if you want to run another query using dbcontext you can try this
var userTree = (from user in users
join location in locations on user.FkHomeLocationId equals location.LocationId
join region in regions on location.RegionId equals region.LocationId
group region by new {
Regionid = region.LocationId,
location.LocationId
}
into grp
select new Application.Alerts.Models.AlertUserTreeViewModel {
RegionName = regions.FirstOrDefault(s = >s.LocationId == grp.Key.Regionid).LocationName,
Branches = new new Application.Alerts.Models.Branch {
BranchId = locations.FirstOrDefault(b = >b.RegionId ==
grp.Key.Regionid).LocationId,
BranchName = locations.FirstOrDefault(b = >b.RegionId == grp.Key.Regionid).LocationName,
Users = users.Where(u = >u.FkHomeLocationId == grp.Key.LocationId).Select(s = >new User {
Id=s.Id,
LastName=s.LastName,
FirstName= s.FirstName
}).ToList()
}
}).ToList();
Your Branch has a List<User> but you are trying to instantiate as a User that's why you are getting the error. Use below code.
Users = users.Where(u = >u.FkHomeLocationId == grp.Key.LocationId).Select(u => new User { FirstName = u.FirstName }).ToList()

Convert stored procedure to Linq statement

I am getting runtime errors when I try and convert this stored procedure to a Linq statement about missing }.I am not sure if I am doing the CASE statement correct in linq. Is there a better way to do this?
SQL
SELECT TOP 1
C.CustomerId,
Institution = (SELECT TOP 1
CASE Name
WHEN 'In1' THEN 'Institution 1'
ELSE Name
END
FROM [Group] G
JOIN CustomerXrefs X ON X.GroupId = G.GroupId AND G.GroupTypeId = 308
WHERE X.CustomerId = C.CustomerId),
G.GroupId
FROM
Customer C
JOIN
CustomerXrefs X ON C.CustomerId = X.CustomerId
JOIN
[Group] G ON X.GroupId = G.GroupId
WHERE
C.Email = #Email
AND G.GroupTypeId = 308
ORDER BY
G.GroupId
Linq
var query1 =
(from c in db.Customers
join cx in db.CustomerXrefs on c.CustomerId equals cx.CustomerId
join g in db.Groups on cx.GroupId equals g.GroupId
select new Customer
{
CustomerId = c.CustomerId,
Institution = (from ig in db.Groups
join icx in db.CustomerXrefs
on ig.GroupId equals icx.GroupId && ig.GroupTypeId == 308
where icx.CustomerId == c.CustomerId
select new Institution
{
Name = ig.Name == "In1 " ? "Institution 1" :
ig.Name == "In2" ? "Institution 2" :
ig.Name
}).FirstOrDefault();
}).FirstOrDefault();
I got rid of all errors by simulating with classes
class Program
{
static void Main(string[] args)
{
DataBase db = new DataBase();
var query1 = (from c in db.Customers
join cx in db.CustomerXrefs on c.CustomerId equals cx.CustomerId
join g in db.Groups on cx.GroupId equals g.GroupId
select new Customer
{
CustomerId = c.CustomerId,
Institution = (from ig in db.Groups
join icx in db.CustomerXrefs on ig.GroupId equals icx.GroupId
where icx.CustomerId == c.CustomerId && ig.GroupTypeId == 308
select new Institution()
{
Name = ig.Name == "In1 " ? "Institution 1" :
ig.Name == "In2" ? "Institution 2" :
ig.Name
}
).FirstOrDefault()
});
}
}
public class DataBase
{
public List<Customer> Customers { get; set; }
public List<CustomerXrefs> CustomerXrefs { get; set; }
public List<Group> Groups { get; set; }
}
public class Customer
{
public string CustomerId { get; set; }
public Institution Institution { get; set; }
}
public class CustomerXrefs
{
public string CustomerId { get; set; }
public string GroupId { get; set; }
}
public class Group
{
public string GroupId { get; set; }
public int GroupTypeId { get; set; }
public string Name { get; set; }
}
public class Institution
{
public string Name { get; set; }
}

LINQ query with Multiple Tables?

I am joining the two tables using LINQ to match model class like below
lstOptInInterest = new LinkedList<OptInInterestArea>
((from a in dbEntities.SUBCODE
from appCode in dbEntities.CODE.Where(
x => x.CODE == a.CODE && x.TYPE == a.TYPE)
select new OptInInterestArea()
{
Code = a.CODE,
SubCode = a.SUBCODE,
SubCodeDescription = a.DESCR,
CodeDescription = appCode.DESCR
}).ToList());
Model class
public class OptInInterestArea
{
[DisplayName("Code")]
public string Code { get; set; }
[DisplayName("Sub Code")]
public string SubCode { get; set; }
DisplayName("Sub Code Description")]
public string SubCodeDescription { get; set; }
[DisplayName("Code Description")]
public string CodeDescription { get; set; }
[DisplayName("Previous OptIn")]
public bool PrevOptIn { get; set; }
}
Table B
Now my question is I need to assign PrevOptIn values of lstOptInInterest from Table B (see above). Table B may or may not contains all of CODE and SUBCODE of lstOptInInterest.
If CODE and SUBCODE of lstOptInInterest exists on the table B assign to PrevOptIn in else PrevOptIn = N
How can I do LINQ to get this?
first, I suggest you use INNER JOIN instead of CROSS JOIN to query your lstOptInInterest :
lstOptInInterest = new LinkedList<OptInInterestArea>
((from a in dbEntities.SUBCODE
join appCode in dbEntities.CODE
on new {CODE=a.CODE,TYPE=a.TYPE} equals new {CODE=x.CODE,TYPE=x.TYPE}
select new OptInInterestArea()
{
Code = a.CODE,
SubCode = a.SUBCODE,
SubCodeDescription = a.DESCR,
CodeDescription = appCode.DESCR
}).ToList());
seconde, use LEFT OUT JOIN to assign PrevOptIn values of lstOptInInterest from Table B :
lstOptInInterest = new LinkedList<OptInInterestArea>
(
(from a in lstOptInInterest
join b in dbEntities.TableB
on new {CODE=a.Code,SUBCODE=a.SubCode} equals new {CODE=b.CODE,SUBCODE=b.SUBCODE}
into leftGroup
from b in leftGroup.DefaultIfEmpty()
select new OptInInterestArea()
{
Code = a.Code,
SubCode = a.SubCode,
SubCodeDescription = a.SubCodeDescription,
CodeDescription = a.CodeDescription,
PrevOptIn=b==null? false : b.OPTIN=="Y"
}).ToList()
);
UPDATE:
Try to test this only 1 steps to get your result:
lstOptInInterest = new LinkedList<OptInInterestArea>
((from a in dbEntities.SUBCODE
join appCode in dbEntities.CODE
on new {CODE=a.CODE,TYPE=a.TYPE} equals new {CODE=x.CODE,TYPE=x.TYPE}
join b in dbEntities.TableB
on new {CODE=a.CODE,SUBCODE=a.SUBCODE} equals new {CODE=b.CODE,SUBCODE=b.SUBCODE}
into leftGroup
from b in leftGroup.DefaultIfEmpty()
select new OptInInterestArea()
{
Code = a.CODE,
SubCode = a.SUBCODE,
SubCodeDescription = a.DESCR,
CodeDescription = appCode.DESCR,
PrevOptIn=b==null?false : b.OPTIN=="Y"
}).ToList());

LINQ LEFT JOIN, Combine multiple WHERE clauses with OR

LINQ,
var clause = PredicateBuilder.False<User>();
clause = clause.Or(u => u.uid.Equals(1));
clause = clause.Or(u => u.uid.Equals(2));
var usersInGroup = (from u in db.Users
join g in db.GroupUsers
on u.uid equals g.uid
into ug
from g in ug.DefaultIfEmpty()
where g.gid.Equals(0)
select u).Where(clause);
These two where clauses are chained together as;
WHERE ([t0].[gid] = 0) AND (([t1].[uid] = 1) OR ([t1].[uid] = 2))
How do I add the two where conditions as
WHERE ([t0].[gid] = 0) OR (([t1].[uid] = 1) OR ([t1].[uid] = 2))
Thanks to,
Can PredicateBuilder generate predicates that span multiple tables?
I now have a solution that works but my result set is based on a new hybrid class. As a result I have had to mirror all of the relevant fields. See below.
public class HybridGroupUser {
private User _user;
public User User {
get { return _user; }
set {
_user = value;
if (value != null) {
uid = value.uid;
fname = value.fname;
lname = value.lname;
email = value.email;
}
}
}
private GroupUser _GroupUser;
public GroupUser GroupUser {
get { return _GroupUser; }
set {
_GroupUser = value;
if (value != null) {
uid = value.uid;
fname = value.fname;
lname = value.lname;
email = value.email;
}
}
}
public int? uid { get; set; }
public string fname { get; set; }
public string lname { get; set; }
public string email { get; set; }
}
With this class I can now do the following;
var clause = PredicateBuilder.False<HybridGroupUser>();
clause = clause.Or(u => u.GroupUser.gid.Equals(0);
foreach (int i in AddedUsers) {
int tmp = i;
clause = clause.Or(u => u.User.uid.Equals(tmp));
}
var usersInGroup = (from u in db.Users
join gusr in db.GroupUser
on u.uid equals gusr.uid
into ug
from gusr in ug.DefaultIfEmpty()
select new HybridGroupUser {
User = u,
GroupUser = gusr
}).Where(clause);
var usersInGroup = (from u in db.Users
join g in db.Groups
on u.uid equals g.uid
where g.gid.Equals(0) || (u.uid.Equals(1) || u.uid.Equals(2))
select u)
Instead of doing multiple Or clauses, why not just do Contains. That way your list of Ids can be complete dynamic (as long as it doesn't exceed 2000):
var ids = new int[] {1, 2, 3};
var usersInGroup = (from u in db.Users
join g in db.GroupUsers
on u.uid equals g.uid
into ug
from g in ug.DefaultIfEmpty()
where g.gid.Equals(0)
&& ids.Contains(u.uid)
select u);

Categories

Resources