I have 3 tables. Orders, OrderItems and OrderItemServices. Each order can contain multiple OrderItems and each OrderItem can contain multiple OrderItemServices.
I want to get a list of data of all orders from these tables in Linq. I could write a join but how do I make an anonymous data type to in select clasue which can give me Order list in this hierarchy?
If I use navigation properties and then select OrderItemServices in side select clause shown below it would fire individual select query for each OrderItemService which I want to avoid.
from order in Orders
select new
{
ActiveOrders = order,
ActiveOrderItems =order.OrderItems,
ActiveServices = order.OrderItems.Select(o => o.OrderItemServices)
}
Is it possible to group each order with a structure of multiple items inside it and multiple services inside items?
Refer msdn to start on LINQ To SQL
To get data from three tables you can get idea from the following simple example
var data = (from product in context.Products
from department in context.Departments
from category in context.Categories
where product.DeptId == department.DeptId
&& product.CatId == category.CatId
select new
{
product.Code,
product.Name,
department.Name,
category.Name
}).Distinct.ToList();
You have to set up your context to use eager loading:
var context = new MyDataContext();
var options = new DataLoadOptions();
options.LoadWith<Orders>(x => x.OrderItems);
options.LoadWith<OrderItems>(x => x.OrderItemServices);
context.LoadOptions = options;
var query = from order in context.Orders // ... etc
Then sub items will be included in initial query result and won't cause additional requests to the database. This will use JOIN internally to retrieve all the data in one go. You can check generated SQL using SQL Server Profiler.
http://blog.stevensanderson.com/2007/12/02/linq-to-sql-lazy-and-eager-loading-hiccups/
Related
How would you implement pagination when the input data needs to be grouped first? I understand how to implement pagination from the link below:
LINQ and pagination
, but I would like to be able to do this where each item in the paginated list is a group (that can be expanded) from the input data. Something similar to the code below - to prevent retrieving all rows of the table into memory, ordersList is IQueryable. The IQueryable returned is what I would like to pass into the pagination function.
from order in ordersList
group order by order.FullName into customers
select customers
However, a query like this runs on the client (and actually throws an exception in Entity Framework Core 3.0+). Is there a way to only retrieve the items on the current page for this situation?
You have to retrieve limited data and then group on the client side:
var keys = ordersList
.Select(o => new {o.FullName})
.Distinct()
.OrderBy(ะพ => o.FullName)
.Skip(pageNumber * pageSize)
.Take(pageSize);
var items =
from order in ordersList
join key in keys on order.FullName equals key.FullName
select order;
var result =
from order in items.AsEnumerable()
group order by order.FullName into customers
select customers;
You must paginate by group. You should use the group number instead of the page number.
//group sequence
int groupSeq = 1;
//select current group
var p = (from order in context.TBLGroups
group order by order.FullName into customers
select customers.Key).OrderBy(a => a).Skip(groupSeq - 1).Take(1).FirstOrDefault();
string FullName = p.ToString();
//get all items in current group
var items = (from order in context.TBLGroups
where order.FullName == FullName
select order).ToList();
I've found plenty of info on how to select multiple result sets with stored procedures but nothing substantial on how to do so with a linq query.
For example, I can do sub-queries that return mulitple sets of results with something like
var query = (from school in context.Schools
where school.id == someId
select new
{
subSetA = (from student in context.Students
select student).ToList(),
subSetB = (from building in context.Buildings
select building).ToList(),
}).First();
query.subSetA; //Access subSetA
query.subSetB; //Access subSetB
Which works fine, but what if I just want to select both subSetA and subSetB without querying against the school table? I want to select two separate sets of data that gets sent to the server in one query.
Any information as to how to do this with EF 6 would be great.
Well, I'm sure there are many ways to do this, but if you want to avoid introducing a third DbSet into the mix...
var query = (from s in context.Students.Take(1)
select new
{
subSetA = context.Students.ToList(),
subSetB = context.Buildings.ToList(),
})
Then, you can use query.ToList() or maybe using query.Load() and working with context.Students.Local, etc. would work.
I am using Linq to SQL in Linqpad to get to some data.
I have 3 tables I need to use to do the following steps:
1) Select customers by postcode (Customer table)
2) Get all transaction ID's for these customers (Transaction table)
3) Get itemized items for all transaxction ID's (Itemized table)
So i start out easy enough and grab the customers:
string pc = "123";
var cust =
from c in Customers
where c.PostCode.StartsWith(pc) == true
select c;
Now I need to create a new Linq object that has the lookup from transaction table based on the "CustomerID" field but I am not sure how to do this. Ive experimented with some foreach loops but cant get syntax right. Did some googling and saw posts saying not to use foreach loops with linq objects as you should use inbuilt Linq functionality but I couldnt find any examples doing what I needed.
I apologise for such a basic question but I have just started using Linq.
How do I create the next Linq object with all transaction records based on the CustoomerID field?
You can use single query with joins. If you have navigation properties in your entities:
from c in Customers
from t in c.Transactions
from i in t.ItemizedItems
where c.PostCode.StartsWith(pc)
select i
Labda syntax:
Customers.Where(c => c.PostCode.StartsWith(pc))
.SelectMany(c => c.Transactions)
.SelectMany(t => t.ItemizedItems);
If you don't have navigation properties:
from c in Customers
join t in Transactions on c.ID equals t.CustomerID
join i in t.ItemizedItems on t.ID equals i.TransactionID
where c.PostCode.StartsWith(pc)
select i
I'm using a self tracking entity model. ProductInstallation is a DTO which contains all the details about the product installation for a company.
The UserRoles entity holds the relationship in-between the Product-System Role-UserID.
As an example:
Product: Inventory
System Role : PurchasingUser
User ID : hasithaH <- (Suppose me)
using the below LINQ query, I can get the distinct UserIDs.
string[] userIDs = productInstallation.UserRoles
.Select(u=>u.UserID).Distinct().ToArray();
now I need to get all the User Profiles for the UserIDs I queried in above steps.
productInstallation.SystemUsers = context.SystemUsers.Select(u=> u.UserID ..???
In SQL point of view, this is the query I want:
Select * from SystemUsers where UserID in ('UserA','UserB','UserC')
How should I write a LINQ query to get this done?
You write it as follows:
var result = context.SystemUsers.Where(su =>
productInstallation.UserRoles.Any(ur => su.UserID == ur.UserId));
Or if both sources are not IQuerable from the same db:
string[] userIDs = productInstallation.UserRoles
.Select(u=>u.UserID).Distinct().ToArray();
var result = context.SystemUsers.Where(su =>
userIDs.Contains(su.UserID));
What you really want to do here is join the two tables. Using a Join you can do this in one query rather than executing two separate queries:
var systemUsers = from userRole in UserRoles
join systemUser in SystemUsers
on userRole.UserID equals systemUser.UserID
select systemUser;
You can try this:
productInstallation.SystemUsers =
context.SystemUsers.FindAll(u=> userIDs.Contains(u.UserID))
How do I update two tables at the same time using Linq-to-SQL?
var z = from a in db.Products
join b in db.ProductSubcategories on
a.ProductSubcategoryID equals b.ProductSubcategoryID
join d in db.ProductCategories on
b.ProductCategoryID equals d.ProductCategoryID
select new { ProductName = a.Name, ProductCategory = d.Name,
ProductSubCategory = b.Name, Cost = a.StandardCost,
discontinuedDate = a.DiscontinuedDate,
ProductId=a.ProductID };
You have to update individual records from each table and then execute db.SubmitChanges();
In your query the output is an anonymous type, not a table type connected to the db context.
If you think in terms of SQL, linq2sql works pretty much the same. You can select a record set with a join, but you cannot update directly on this. You need to break it up and modify entries directly on Products, ProductCategories and ProductSubCategories, which equals the tables in your database.
If you want to modify a Product in Products then you have to modify the properties of that type, and not the anonymous type (joined type).