I group the result on the customers zipcode. For each zipcode, I want to see the amount of bookings and the amount of equipment that is ordered.
So far my code looks like this:
var statistics = from b in db.Bookings
from c in db.Customers
where b.customerID == c.id
group c by c.zipcode into stat
select new {
Zipcode = stat.Key,
NumberOfBookings = stat.Count()
};
This code groups result into zipcodes and gives me the amount of bookings in each zipcode. How to get the amount of equipment also?
Rather than using joins like in SQL, you can (and it's better) use the navigation properties from your model:
var statistics =
from b in db.Bookings
group b by b.Customer.zipcode into g
select new
{
Zipcode = g.Key,
NumberOfBookings = g.Count(),
NumberOfEquipments = g.SelectMany(b => b.Equipments).Count(),
};
Note that the g variable represents a set of bookings with the same zipcode, so SelectMany is used to get all associated equipments before applying the Count operator.
Of course that's not the only way, for instance you can use Sum instead:
NumberOfEquipments = g.Sum(b => b.Equipments.Count())
Related
I'm currently having a problem on sql statement
here's my code
SELECT [Cities].ProvinceId,[Cities].Name,[Provinces].Name
FROM [Cities] JOIN Provinces
ON [Cities].ProvinceId = [Provinces].id
UNION
SELECT [Regions].RegionName,[Countries].CountryName
FROM [Regions] JOIN Countries
ON [Regions].RegionId = [Countries].RegionId
so basically what I am trying to do is that get the cities,province,region and countries.
I have 4 regions by the way which is
ASEAN = 1,ASIA = 2,WORLDWIDE = 3,DOMESTIC = 4
so DOMESTIC needs to be on the cities and province only because they are places local here in my country
and regions 1,2,3 are for countries but I could join theme because of these error
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
by the way I Applied it like this on my API
var provinces = await _provinceRepository.GetAll();
var cities = await _cityRepository.GetAllCities();
var result = provinces.Join(cities, p => p.Id, c => c.ProvinceId, (p, c) =>
new DestinationModel
{
Region = null,
City = c.Name,
State = p.Name,
Continent = null,
Country = null
}).ToList();
return Ok(result);
Now you can see my problem is that for now I can only get provinces and cities
the region and country are still null. Could someone help me with my query.
so basically what I am trying to do is that get the cities,province,region and countries.
Does this do what you want?
SELECT c.Name as city, p.Name as province, co.name as country,
r.name as region
FROM Cities c
JOIN Provinces p ON c.ProvinceId = p.id
JOIN Countries co ON p.CountryId = co.id
JOIN Regiones r ON co.RegionId = r.id;
To me, it seems like a more sensible result.
I've been looking at other threads here to learn how to do a GroupBy in linq. I am following the EXACT syntax that has worked for others, but, it's not working.
Here's the query:
var results = from p in pending
group p by p.ContactID into g
let amount = g.Sum(s => s.Amount)
select new PaymentItemModel
{
ContactID = g.ContactID, // <--- Error here
Amount = amount
};
pending is a List<T> that contains, among other columns, ContactID and Amount, but those are the only two I care about for this query.
The trouble is, inside the the select new, the g. won't give me any of the columns inside the original list, pending. And when I try, I get:
IGrouping <int, LeadPurchases> does not contain a definition for ContactID, and no extension method blah blah blah...
This is the SQL I am trying to emulate:
SELECT
lp.PurchasedFromContactID,
SUM (lp.Amount)
FROM
LeadPurchases lp
GROUP BY
lp.PurchasedFromContactID
You are grouping on the basis of ContactID, so it should be the Key for the result, So you have to use g.Key instead of g.ContactID; Which means the query should be like the following:
from p in pending
group p by p.ContactID into g
let amount = g.Sum(s => s.Amount)
select new PaymentItemModel
{
ContactID = g.Key,
Amount = amount
};
updates :
If you want to perform grouping based on more than one column then the GroupBy clause will be like this:
group p by new
{
p.ContactID,
p.Field2,
p.Field3
}into g
select new PaymentItemModel()
{
ContactID = g.Key.ContactID,
anotherField = g.Key.Field2,
nextField = g.Key.Field3
};
I'm trying to get back a list of TransferIds, for each transfer a list of ChargeIds, and for each of those a list of ReferralMatches
here is what I've got
(from c in Commissions
where c.TransferStatus == "Paid"
where c.AdminHasReleased == false
join r in ReferralMatches on c.ReferralMatchId equals r.ReferralMatchId
group c by new { c.TransferId } into grp
select new {
TransferId = grp.Key.TransferId,
Charges = from c in grp
group c by c.ChargeId into grp2
select new {
ChargeId = grp2.Key,
Referrals = grp2 }
})
This works and is very close. It pulls back something that looks like this:
This looks like Charges that belong to a TransferId but what I need is ReferralMatches that belong to Charges that belong to a transferId. I've tried another select to pull in 'r' but running into errors.
I think LINQ people will be able to gather what they need from this post but if more info is needed, kindly let me know. Thank you.
EDIT, adding table samples
The two expanded tables are what I have to work with. It probably isn't useful but keep in mind that the ReferralMatch table also has ChargeId. One chargeId can cover multiple ReferralMatches but once the funds are available a bank transfer occurs...when that happens, records are created in the Commissions table.
So what I'm looking for is a list of TransferIds, foreach Id a list of chargeIds, and foreach chargeId a list of ReferralMatches...the innermost list of ReferralMatches would be full records from that table.
EDIT, more attempts
here's my latest attempt
from c in Commissions
where c.TransferStatus == "paid"
group c by c.TransferId into transferGroup
select new {
TransferId = transferGroup.Key,
Charges = from c in transferGroup
join r in ReferralMatches on c.ReferralMatchId equals r.ReferralMatchId
group c by c.ChargeId into chargeGroup
select new {
ChargeId = chargeGroup.Key,
Referrals = from r in chargeGroup
select new {
Referral = r
}
}
}
which pulls up something like this:
but unless I'm reading this incorrectly, the innermost item is still commission table which doesn't make sense. I need that to be ReferralMatches that have a ChargeId of [whatever]
You might need to separate out the expression into two and pull through the Referrals in the first expression, and then group on a second expression as follows:
var commissionAndReferrals =
from c in Commissions
where c.TransferStatus == "Paid"
where c.AdminHasReleased == false
join r in ReferralMatches on c.ReferralMatchId equals r.ReferralMatchId
select new { Commisson = c, Referral = r };
var result =
from cAndR in commissionAndReferrals
group cAndR by cAndR.Commisson.TransferId into transferGroup
select new
{
TransferId = transferGroup.Key,
Charges = from c in transferGroup
group c by c.Commisson.ChargeId into chargeGroup
select new
{
ChargeId = chargeGroup.Key,
Referrals = chargeGroup.Select(x => x.Referral)
}
};
I have two tables in my database:
Town:
userid, buildingid
Building:
buildingid, buildingname
What i want is to populate a GridView like this:
But I don't want the buildings to be shown more than once. Here is my code:
var buildings = dc.Towns
.Where(t => t.userid == userid)
.GroupJoin(dc.Buildings,
t => t.buildingid,
b => b.buildingid,
(Towns, Buildings) => new
{
BuildningName = Buildings.First().buildingname,
Count = Towns.Building.Towns.Count()
});
gvBuildings.DataSource = buildings.ToList();
gvBuildings.DataBind();
New code which works:
var buildings = (from t in dc.Towns
where t.userid == userid
join b in dc.Buildings
on t.buildingid equals b.buildingid
into j1
from j2 in j1.DefaultIfEmpty()
group j2 by j2.buildingname
into grouped
select new
{
buildingname = grouped.Key,
Count = grouped.Count()
});
gvBuildings.DataSource = buildings.ToList();
gvBuildings.DataBind();
var buildings = from t in dc.Towns
join b in dc.Buildings on t.buildingid equals b.buildingid into j1
from j2 in j1.DefaultIfEmpty()
group j2 by b.buildingname into grouped
select new { buildingname = grouped.key, Count = grouped.Count()}
I think this should do it. I have not tested it so it might give error but it will be something like this.
Wouldn't something like this do it?
Users
.Select(User => new {User, User.Building})
.GroupBy(x => x.Building)
.Select(g=> new {Building = g.Key, Count = g.Count()})
According to my experience with Linq to SQL, when the expression is becoming complicated it is better to write a stored procedure and call it with Linq to SQL. In this way you get better maintainability and upgradeability.
Rather than an option to pure SQL, I see “Linqu to SQL” as a tool to get hard typed object representation of SQL data sets. Nothing more.
Hope it helps you.
Example scenario:
Two tables: order and orderItem, relationship One to Many.
I want to select all orders that have at least one orderItem with price 100 and at least one orderItem with price 200.
I can do it like this:
var orders = (from o in kontextdbs.orders
join oi in kontextdbs.order_item on o.id equals oi.order_id
join oi2 in kontextdbs.order_item on o.id equals oi2.order_id
where oi.price == 100 && oi2.price == 200
select o).Distinct();
But what if those conditions are user generated?
So I dont know how many conditions there will be.
You need to loop through all the values using a Where and Any method like this:
List<int> values= new List() { 100, 200 };
var orders = from o in kontextdbs.orders
select o;
foreach(int value in values)
{
int tmpValue = value;
orders = orders.Where(x => kontextdbs.order_item.Where(oi => x.id == oi.order_id)
.Any(oi => oi.price == tmpValue));
}
orders = orders.Distinct();
List<int> orderValues = new List() { 100, 200 };
ObjectQuery<Order> orders = kontextdbs.Orders;
foreach(int value in orderValues) {
orders = (ObjectQuery<Order>)(from o in orders
join oi in kontextdbs.order_item
on o.id equals oi.order_id
where oi.price == value
select o);
}
orders = orders.Distinct();
ought to work, or at least that's the general pattern - you can apply extra queries to the IObjectQueryables at each stage.
Note that in my experience generating dynamic queries like this with EF gives terrible performance, unfortunately - it spends a few seconds compiling each one into SQL the first time it gets a specific pattern. If the number of order values is fairly stable though then this particular query ought to work OK.