linq to sql LoadWith limiting fields returned - c#

Is there a way to use LoadWith but specify the fields that are returned?
For example, if I have two tables 1) Products 2) Categories
and do something like
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Products>(d => d.Categories);
db.LoadOptions = dlo;
MyDataContext db = new MyDataContext();
var result = from d in db.Products
select d;
when i check the query in profiler i see that ALL the rows from the Categories table are being returned. All I really need is the "Name" field.
I know I can rewrite the query using joins but I need to return the result set as a "Product" data type which is why I am using LoadWith.

No that's not possible with LoadWith.
You could try with a nested query in the projection, though that will be slow: 1 query per parent (so 1 query for the related category per product loaded).

You can use a projection, but you need to deal with anynomus types after that
select new {Order = order, ProductName = order.Product.Name,
CustomerName = order.Customer.Name,
OrderType = order.OrderType.Name } // etc

Related

Apply where condition on the child table in Linq to SQL

I have a table TableA and child table TableB. I want to fetch all the parent table records,
but select child records which satisfy a condition. I am using include to get the child records.
Is there any direct way other than using select new?
LINQ to SQL has a LoadOptions that you can set on the context to do some powerful things. Most people point to the .LoadWith which eagerly loads child records. There's also an AssociateWith which specifies the filtering to apply on lazy child fetches. Both of them can take a lambda expression for sub child filtering. Here's an example:
var lo = new DataLoadOptions();
lo.AssociateWith<Customers>
(c => c.Orders.Where(o => !o.ShippedDate.HasValue));
this.LoadOptions=lo;
var query = from c in Customers
select c.Orders;
Note, this only works with LINQ to SQL. EF does not support this behavior at this time.
using (var context = new DbEntities()) {
foreach (var p in context.Parents) {
var childQuery = from c in p.Children
where c.whatever == something
select c;
// Do something with the items in childQuery, like add them to a List<Child>,
// or maybe a Dictionary<Parent,List<Child>>
}
}

Join vs Navigation property for sub lists in Entity Framework

I have a sql statement like this:
DECLARE #destinations table(destinationId int)
INSERT INTO #destinations
VALUES (414),(416)
SELECT *
FROM GroupOrder grp (NOLOCK)
JOIN DestinationGroupItem destItem (NOLOCK)
ON destItem.GroupOrderId = grp.GroupOrderId
JOIN #destinations dests
ON destItem.DestinationId = dests.destinationId
WHERE OrderId = 5662
I am using entity framework and I am having a hard time getting this query into Linq. (The only reason I wrote the query above was to help me conceptualize what I was looking for.)
I have an IQueryable of GroupOrder entities and a List of integers that are my destinations.
After looking at this I realize that I can probably just do two joins (like my SQL query) and get to what I want.
But it seems a bit odd to do that because a GroupOrder object already has a list of DestinationGroupItem objects on it.
I am a bit confused how to use the Navigation property on the GroupOrder when I have an IQueryable listing of GroupOrders.
Also, if possible, I would like to do this in one trip to the database. (I think I could do a few foreach loops to get this done, but it would not be as efficient as a single IQueryable run to the database.)
NOTE: I prefer fluent linq syntax over the query linq syntax. But beggars can't be choosers so I will take whatever I can get.
If you already have the DestinationGroupItem as a Navigation-property, then you already have your SQL-JOIN equivalent - example. Load the related entities with Include. Use List's Contains extension method to see if the desired DestinationId(s) is(are) hit:
var destinations = new List<int> { 414, 416 };
var query = from order in GroupOrder.Include(o => o.DestinationGroupItem) // this is the join via the navigation property
where order.OrderId == 5662 && destinations.Contain(order.DestinationGroupItem.DestinationId)
select order;
// OR
var query = dataContext.GroupOrder
.Include(o => o.DestinationGroupItem)
.Where(order => order.OrderId == 5662 && destinations.Contain(order.DestinationGroupItem.DestinationId));

LINQ Projected Filtering C#

I want to filter my LINQ query based on an included table but am having some trouble.
Here is the original statement, which works:
return
this.ObjectContext.People.
Include("Careers").
Include("Careers.Titles").
Include("Careers.Titles.Salaries");
Now I'm trying to filter on Careers using projected filtering but am having trouble. It compiles but it leaves out the Titles and Salaries tables, which causes runtime errors, and I can't seem to add those tables back in:
var query1 = (
from c in
this.ObjectContext.People.
Include("Careers").
Include("Careers.Titles").
Include("Careers.Titles.Salaries")
select new
{
c,
Careers = from Careers in c.Careers
where Careers.IsActive == true
select Careers
});
var query = query1.AsEnumerable().Select(m => m.c);
return query.AsQueryable();
How can I include the titles and salaries tables in the filtered query?
You can simplify your query considerably, which should resolve your issue. I'm assuming that you want all people with at least 1 active career:
var query =
from c in
this.ObjectContext.People.
Include("Careers").
Include("Careers.Titles").
Include("Careers.Titles.Salaries")
where c.Careers.Any(c => c.IsActive);
return query;
I would try something like,
var query = from p in ObjectContext.People
join c in ObjectContext.Careers on p equals c.Person
where c.IsActive
select p;

Use LINQ-to-SQL to return an object that has child objects filtered

I have a MembershipGroups table that is associated with a child Members table. The Members table has a Status column which can be set to Active or Inactive.
I want to select all MembershipGroups and only their active Members
As an example,
MembershipGroups
ID----Title
1-----Group #1
2-----Group #2
Members
MembershipGroupID-Name--Status
1-------------------------John----Active
1-------------------------Sally----Inactive
1-------------------------David---Inactive
I'm trying to create a query that looks something like the following (which doesn't currently work):
var query = from mg in db.MembershipGroups
where mg.Members.Status = "Active"
select mg
The result for this example should return a MembershipGroup of ID#1 with only one child Member entity
How can use LINQ-to-SQL to select a parent object that filters on child objects? If I were using straight T-SQL then this would be a simple join with a where clause but it seems to be much more difficult to do using LINQ-to-SQL.
Edit - Updated answer to return the MemberShipGroup object
var query = (from mg in db.MembershipGroups
join m in db.Members.Where(mem => mem.Status == "Active")
on mg.ID equals m.MembershipGroups into members
select new
{
MembershipGroup = mg,
Members = members
}).AsEnumerable()
.Select(m => new MembershipGroup
{
ID = m.MembershipGroup.ID,
Title = m.MembershipGroup.Title,
Members = m.Members
});
In LINQ to SQL, you can use the AssociateWith method on the DataLoadOptions to set your child filter at the context level.
DataLoadOptions opt = new DataLoadOptions();
opt.AssociateWith<Member>(m => m.Status == "Active");
db.LoadOptions = opt;
With this in place, you can simply return your member groups (or filter them for the active ones using where mg.Any(group => group.Members.Status == "Active"). Then when you try to drill into the Members of that group, only the Active ones will be returned due to the LoadOptions.
See also http://msdn.microsoft.com/en-us/library/system.data.linq.dataloadoptions.associatewith.aspx .
One word of warning, once you set the LoadOptions on a context instance, you can not change it. You may want to use a customized context to use this option.
As an alternative, you could use LINQ to SQL's inheritance model to create an ActiveMember type using the Status column as your discriminator and then create an association between the MemberGroups and ActiveMembers types. This would be the approach you would need to use to model this with the Entity Framework if you though about going that route as well as EF doesn't support the concept of the LoadOptions.
Make sure you are including the child objects you are trying to filter on, inside the query.
E.g.
var query = db.MembershipGroups
.Include("Members")
.Where(m => m.Members.Status == "Active");

Use calculated / scalar value in LINQ query

I'm using LINQ on a Telerik OpenAccess generated data model, to setup a search query and get the results. This all works very well and the code looks very nice.
But now i need to add one more thing, and i'm not sure how to.
The products i'm selecting should have a different price for each customer. The price depends on some other values in 2 other SQL tables. Right now i have the price calculation in a SQL scalar function, but i'm not sure on how to use that in combination with my LINQ.
My goal is to retrieve all data in one database roundtrip, and to be able to sort on this calculated price column as well.
Right now i have something like:
var products = (from p in Products select p);
if(searchOption)
products = products.Where(product => product.Name.Contains(searchOption));
products = products.OrderByDescending(product => product.Name);
products = products.Skip(pageNr * pageSize).Take(pageSize);
I can, of course, use all properties of my Product class, but i want to be able to use a new virtual/calculated property, let say: Product.CalculatedPrice as well.
I have a feeling it should look a bit like this.
(from p in Products
select new {
productId = p.ProductId,
name = p.Name,
calculatedPrice = CalculatedValueFromStoredProcedure/OrScalarFunction(p.ProductId, loggedInCustomerId)
});
Best Regards, Tys
.Select() allows you to create a dynamic type, in which you can extend the product with the calculated price
products.Select(i => new { Product = i, CalculatedPrice = 100})
or in your initial line:
var products = (from p in Products select new { Product = p, CalculatedPrice = 100 });
After doing some more research i've found out that what i want to do is NOT possible in combination with the Telerik OpenAccess ORM! So i've created a workaround that pre-calculates the values i need, put them in a table and join my selection with the contents of that table.
For now, that's the best possible solution i've found.

Categories

Resources