EF Sum between 3 tables - c#

Say we got a Database design like this.
Customer
Id Name
1 John
2 Jack
Order
Id CustomerId
1 1
2 1
3 2
OrderLine
Id OrderId ProductId Quantity
1 1 1 10
2 1 2 20
3 2 1 30
4 3 1 10
How would I create an entity framework query to calculate the total Quantity a given Customer has ordered of a given Product?
Input => CustomerId = 1 & ProductId = 1
Output => 40
This is what I got so far, through its not complete and still missing the Sum.
var db = new ShopTestEntities();
var orders = db.Orders;
var details = db.OrderDetails;
var query = orders.GroupJoin(details,
order => order.CustomerId,
detail => detail.ProductId,
(order, orderGroup) => new
{
CustomerID = order.CustomerId,
OrderCount = orderGroup.Count()
});

I find it's easier to use the special Linq syntax as opposed to the extension method style when I'm doing joins and groupings, so I hope you don't mind if I write it in that style.
This is the first approach that comes to mind for me:
int customerId = 1;
int productId = 1;
var query = from orderLine in db.OrderLines
join order in db.Orders on orderLine.OrderId equals order.Id
where order.CustomerId == customerId && orderLine.ProductId == productId
group orderLine by new { order.CustomerId, orderLine.ProductId } into grouped
select grouped.Sum(g => g.Quantity);
// The result will be null if there are no entries for the given product/customer.
int? quantitySum = query.SingleOrDefault();
I can't check what kind of SQL this will generate at the moment, but I think it should be something pretty reasonable. I did check that it gave the right result when using Linq To Objects.

Related

Combining two tables and writing a query from them into a list

I have 2 tables in the database - Customer and Product.
I perform the selection by skipping the first row in the table and then getting the top two rows.
The result I need to get in the List cusPod .
List<Customer> customers = db.Database.SqlQuery<Customer>("SELECT * FROM Customers ORDER BY CustomerId OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY").ToList();
List<Product> products = db.Database.SqlQuery<Product>("SELECT * FROM Products ORDER BY ProductId OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY").ToList();
var listSas = from p in products
join c in customers on p.ProductId equals c.CustomerId
select new { ProductId = p.ProductId, ProductName = p.ProductName, DateStart = p.DateStart, DateEnd = p.DateEnd, DateRegister = p.DateRegister, PriceCustomer = p.PriceCustomer, CheckPay = p.CheckPay, CustomerId = p.CustomerId, FIO = c.FIO, Email = c.Email, PhoneNumber = c.PhoneNumber };
SidebarController.cusPod = listSas.ToList();
how do I do this right?
From the code it seems that you are using entity framework as your ORM, therefore, you can easily use the Skip and Take methods of EF that are great features instead of writing hard coded sql. for example:
db.Customers.OrderBy(c => c.CustomerId).Skip(1).Take(2);
The rest of your logic seems fine.

How to select and exclude records from the same subset in LINQ

I have a sample connection table PolicyToX with fields Id, PolicyId, PersonId, SchoolId. Records are always saved with one of the FKs being NULL, for example 1, 1, 5, NULL.
I want to write a query in LINQ that, when given two parameters: PersonId and SchoolId will filter all Policies of the given School but without those that are already bound to a given Person.
So, if I have a dataset of:
[Id][PolicyId][PersonId][SchoolId]
1 1 5 NULL
2 1 NULL 1
3 2 NULL 1
and pass paremeters PersonId = 5 and SchoolId = 1 the result should be one Policy of ID = 2.
Thanks!
Assuming PolicyToX contains the data then is this what you're looking for?
var ids = from e in PolicyToX where e.PersonId == personId select e.PolicyId;
var result = from d in PolicyToX where d.SchoolId == schoolId && !ids.Contains(d.PolicyId) select d;
var data = list.Where(x => x.SchoolId == schoolId && x.PersonId != personId);
Are you talking about this?

Linq Query for EAV design table

I had a situation to use EAV design tables and I am new to this design,I am struck with a select query. Below is my query structure and data.
TABLE1:
Id KeyName
1 Name
2 Age
TABLE2:
ID TABLE1_ID VALUE
1 1 ABC
2 2 12
3 1 CDF
4 2 14
5 1 XYZ
6 2 13
7 1 CSF
8 2 10
EXPECTED OUTPUT: Get all the values which are greater than 12 AND Value contains "C".
i.e.,
Table2_ID Result Table1_KeyName
1 ABC Name
2 12 Age
3 CDF Name
4 14 Age
Options I tried are:
Var temp = (from c in Table2
where c.Value > 12 && c.Table1.KeyName.Contains("C")
Select new
{
ID = c.ID,
Result = C.Value
});
the above query didn't returned any result, as filters(in where clause) are across rows. I even tried "OR" condition in where clause, it returns me everything. Please do help me.
Your query is wrong, did you type it in here or copy and paste it from your work?
Do you have this table setup in an ORM such as Entity Framework? So that there is a relationship setup between table1 and table2, so you don't have to 'join' them?
To be more 'correct' it should be...
Var temp = (from c in Table2
where c.Value > 12 && c.Table1.Name.Contains("C")
Select new
{
ID = c.ID,
Name = c.Table1.Name,
Value = c.Value
});
Or if the relationship isn't in an ORM your using explicitly specify the join as follows:
Var temp = (from c in Table2
join c1 in Table1 on c.Table1_ID equals c1.Id
where c.Value > 12 && c.Table1.Name.Contains("C")
Select new
{
ID = c.ID,
Name = c.Table1.Name,
Value = c.Value
});
Edit: then it should be an OR, not AND
Var temp = (from c in Table2
where c.Value > 12 || c.Value.Contains("C")
Select new
{
ID = c.ID,
Result = c.Value,
KeyName = c.Table1.Name
});

Linq query help

Is there a way to write a Linq statement to find duplication in Column B, and only find it when Column A has duplicated values then add the value of Column B to the Column where the duplication is found. Any help is appreciated thanks.
RecordID CartID Quantity ProductID
1 11 3 3
2 12 5 6
3 11 6 3
Delete record 3 and add 6 to the Quantity of RecordID 1 so that it becomes:
RecordID CartID Quantity ProductID
1 11 9 3
2 12 5 6
var records = (from i in list
group i by i.CartID into g
select new Item()
{
RecordID = g.Min(o => o.RecordID),
CartID = g.Key,
Quantity = g.Sum(o => o.Quantity),
ProductID = g.Min(o => o.ProductID)
}).ToList();
This sums all the quantity of items with the same CartId creating only the min occurent RecordId and ProductId as you asked. Selecting the min ProductId is something I needed to do to make the query work.
That is why I think you miss some grouping on ProductId...
You did not ask for this, but I think this is what you want (because it makes common sense to not group apples and pears together). (It gives the same result on the sample data provided but for different ProductsIds it will have different results.
var records = (from i in list
group i by new { cartID = i.CartID, prodID = i.ProductID } into g
select new Item()
{
RecordID = g.Min(o => o.RecordID),
CartID = g.Key.cartID,
Quantity = g.Sum(o => o.Quantity),
ProductID = g.Key.prodID
}).ToList();
This groups by CartID and ProductId. Multi-field grouping in Linq is achieved with anonymous types.

LINQ to SQL, get most recent records for given ID

intHi,
Pretty new to LINQ.
I have a Ratings table.
A User adds a set of Ratings for an Entity
There can be more than one Rating set for an Entity per User.
For example, let's say the Entity is a car. The car is rated on Appearance and Performance. And a User can rate the given car's appearance and performance more than once. So my table looks something like this (the Rating field is not an Identity column; it is an int on a scale of 1 - 10):
ReviewID UserID EntityID CatID Rating Body DateSubmitted
1 3 6 1 7 "drives great" 8/01/2010 02:36:28 PM
2 3 6 2 8 "looks great" 8/01/2010 02:36:28 PM
3 3 6 1 2 "broke down" 8/18/2010 11:39:58 PM
4 3 6 2 1 "paint flaked off" 8/18/2010 11:39:58 PM
Now, I have a helper method where I supply the UserID and the EntityID and I want to return the most recent set of Ratings (into a ViewModel that includes the Rating Category).
public static IQueryable<RatingViewModel> GetRatingViewModel(int EntityID, int UserID)
{
DB _db = new DB();
var a =
from rating in _db.Ratings
join ratingCat in _db.RatingCategories
on rating.RatingCategoryID equals ratingCat.RatingCategoryID
where rating.UserID == UserID
&& rating.EntityID == EntityID
select new RatingViewModel
{
Rater = rating.User,
RaterRating = rating,
RatingCategory = ratingCat
};
return a;
}
What kind of "where" or "group by" or "order by" do I need to add to ONLY grab the most recent set of Ratings for the given UserID and EntityID?
Thanks!
Consider ordering by the DateSubmitted on the return of the method, and then taking the number of entries that you'd like.
var a = from rating in _db.Ratings
join ratingCat in _db.RatingCategories
on rating.RatingCategoryID equals ratingCat.RatingCategoryID
where rating.UserID == UserID
&& rating.EntityID == EntityID
orderby rating.DateSubmitted descending
select new RatingViewModel
{
Rater = rating.User,
RaterRating = rating,
RatingCategory = ratingCat
}
.Take(10);
.OrderByDescending(a => a.DateSubmitted).FirstOrDefault()

Categories