I have a many-to-many relationship where Content has ContentTags which point to a Tag. I've put the relevant [Include] attributes on my entities to create the properties.
If I write enumerate ObjectContext.Contents.Include("ContentTags.Tag") then I get the ContentTags and Tags included as expected. When I use a join however the ContentTags are missing from my Content entity:
var contentsForTag =
from c in ObjectContext.Contents.Include("ContentTags.Tag")
join ct in ObjectContext.ContentTags on c.Id equals ct.ContentId
join t in ObjectContext.Tags on ct.TagId equals t.Id
where t.Name.ToLower().Contains(lowerTag)
select c;
Any ideas what's going on here?
I'm not sure why this is happening but I think it is because of a contradiction.
The join says that EF should load only the tags that containes lowerTag but the Include says that all tags should be loaded. I would guess EF can't resolve this and that is why none are included. You should be able to write your query without the join though
var contentsForTag =
from c in ObjectContext.Contents.Include("ContentTags.Tag")
where c.ContentTags.Any(ct => ct.Tag.Name.ToLower().Contains(lowerTag))
select c;
Try the following:
var anonType =
from c in ObjectContext.Contents
join ct in ObjectContext.ContentTags on c.Id equals ct.ContentId
join t in ObjectContext.Tags on ct.TagId equals t.Id
where t.Name.ToLower().Contains(lowerTag)
select new { Contents = c, ContentTags = ct, Tags = t }).AsEnumerable();
IList<Contents> contentsForTag = anonType.Select(c => c.Contents).ToList();
If you drop all relevant tables into an anonymous type EF will understand that you in fact need all of that info and will bring it back. The best part is that EF will also take care of the auto-fixup, meaning all relationships will be maintained. The last line of the sample simply extracts the desired objects from the anonymous type into a strongly typed list, however the rest of the graph is still alive and well.
Sounds like a "lazy-load" vs "eager-load" difference. The collection of Tags for a Content class is stored in a child table. Many ORMs including EF try to "lazy-load" collections and other many-to-one references, because it doesn't know if you'll need them and it would be a waste of bandwidth if you didn't. However, this means your tags aren't available in retrieved instances. To tell L2E that, yes, you really do need the tags, you specify that the child reference should be "eagerly" traversed when building the context.
Related
I'm trying to join two different class models in an MVC project together so I can order them ascending/descending. I've tried several permutations but can't seem to get the LINQ query to play nice. Any suggestions on what I'm doing wrong?
var lateContact = from c in JPLatestContact
join s in JPStudent on c.ApplicationUserId equals
s.ApplicationUserId
orderby c.JPLatestContactDate ascending
select s;
I'm a beginner when it comes to this, but if I'm understanding this correctly, the "c" and "s" are variables I make up myself. "JPLatestContact" and "JPStudent" are the two models/classes/tables I want to join, and both have "ApplicationUserId" that I can join them on, and I want to order all the results by the value "JPLatestContactDate" found in the JPLatestContact model, in ascending order.
With the query I've written above, I'm getting a CS0119 error "'JPLatestContact' is a type, which is not valid in the given context."
I'm not sure where I'm going wrong with my structure, or have I misused the JOIN structure in some way?
You cannot run a LINQ select on a type, only on a collection of that type - i.e. anything that implements IEnumerable<JPLatestContact> or IQueryable<JPLatestContact>, such as List<JPLatestContact>, dbContext.JPLatestContact, etc. Same goes for JPStudent - you need a collection or IQueryable<JPStudent> for it.
Assuming that you are querying EF, the query should look like this:
var lateContact = from c in dbContext.JPLatestContact
join s in dbContext.JPStudent on c.ApplicationUserId equals
s.ApplicationUserId
orderby c.JPLatestContactDate ascending
select s;
Make sure that all entity names and property names match the actual names as defined in your EF model.
I have been having a problem with the following query I constructed it keeps returning null, I am hoping that someone could just point me in the right direction.
The query is meant to return a list of branches that offer a particular service based on a service ID that is given. I have a many-to-many relationship between two tables being branches and services.
from b in database.branches
join bs in database.branch_services on b.branch_id equals bs.branch_id
where bs.service_id == objID
select b;
Here is the valid query, adjust table names to match yours:
database.Services.Where(s => s.ServiceId == 3).First().Branches.ToList();
Have you tried the lambda syntax?
I want to perform a nested select statement in linq the form of:
select *
from table_a
where w in (select w
from table_b
where x in (select x
from table_c
where z in (select z
from table_d
where z = z)))
The problem is, the only way I can figure out how to do that is by loading the results from table_b and table_c, which adds an unnecessary expense. For example, say I am attempting to load all of a customer's orderdetaildetails. The following code will load ALL of MyCustomer's orders and ALL of each order's orderdetails and, only then, all of each orderdetail's orderdetaildetails:
customer MyCustomer; //Entity customer already loaded.
var query = MyCustomer.orders.SelectMany(order => order.orderdetails).SelectMany(od => od.orderdetaildetails);
Another approach is to use the .Include function. However, this also loads each level:
var query = MyCustomer.orders.CreateSourceQuery().Include("orderdetails.orderdetaildetails");
Both of these functions load unnecessary data. The first, SelectMany(), actually makes separate roundtrips to the database for each navigation level and then for each returned entity (save entities on the last navigation level). Include() makes one trip to the database and does one giant join statement. This is a little better, but still unseemly.
Is there a way to reach the ordetaildetails level (from customer) WITHOUT loading orders and orderdetails into memory AND in one trip to the database only?
Thanks guys - Lax
This should get you the orderdetaildetails for a given customer without unnecessary loading.
customer MyCustomer; // Entity customer already loaded
var orderDetailsDetails = context.OrderDetailsDetails
.Where(odd => odd.OrderDetail.Order.Customer.CustomerPK == customer.CustomerPK);
It looks like you have lazy loading enabled which means that as soon as you access the customers orders EF goes off to the database to get them for you. It's the same when ever you access the orders orderdetails. An alternative method similar to what you used would be.
var query = context.Customers.Where(c => c.CustomerPK == customer.CustomerPK)
.SelectMany(c => c.orders)
.SelectMany(order => order.orderdetails)
.SelectMany(od => od.orderdetaildetails);
I am using the entity framework database first to build a model of my database. Up to this point I have worked on single tables/entities and it has gone quite smooth to get the data with a query and saving it in a list in order to present the data.
Now I am in a situation where I need to join several tables and find myself in a bit of a struggle. I thougth I could simply join the entities I need since they have a foreign key to eachother, but I am having trouble finding a query that returns the set I want, which is basicly all columns from all tables.
In t-sql I would simply do a LEFT JOIN on the different tables on the keys. I have considered creating a view and then build the model on this view, but I have to be able to update the data as well and a view from the database is not so straight forward to update with the EF as far as I have understood.
I was hoping to do something like the query below, but since I need to update the different tables as well I was wondering if anyone has an elegant solution for how to do this. Or is it something I simply have not understood about joining in EF?
using(var _ctx = new EFEntities())
{
var queryResult = from a in _ctx.a
join b in _ctx.b
on a.b_ID equals b.ID
join c in _ctx.c
on b.c_IDequals c.ID
select new
{
//columns I want
};
}
As has already been mentioned in the comments there should be navigation properties between your classes but if you really want to flatten the data but maintain objects that can be updated elsewhere then you could do something like this:
using(var _ctx = new EFEntities())
{
var queryResult = from a in _ctx.a
join b in _ctx.b
on a.b_ID equals b.ID
join c in _ctx.c
on b.c_IDequals c.ID
select new
{
a = a,
b = b,
c = c
};
}
i have tableA and tableB
tableA has a B_Id property.
This query works fine:
IEnumerable<A> a = Session.Query<A>().Fetch(r=>r.B);
but i want something like:
IEnumerable<A> a = Session.Query<A>().Where(r=>r.B.Active).Fetch(r=>r.B);
it seems like when i do this, it no longer does a simple outer join and if there are no active records in table B, i get no results.
I want to do a pure outerjoin that will still give me results but with the B property of the A entity as null.
Does nhibernate LINQ support this ability to put a where clause on your outerjoined table??
According to this post on the nhusers group it's apparently not supported, and you'll have to use HQL.
As to the why, I would speculate that the authors plan to add it but had higher priorities. Personally I'd see it as a key feature.
Guess: .Where(a => a.B == null || a.B.Active)
A thought: You're trying to select instances of A which will be in an unknown state. How should NHibernate differ between instances of A where B == null and B.Active == false?
Both will, if it worked, return null values for B and A would be populated with a null reference. What should happen if you save A again? Should the reference to B be set to null? That would remove references when B.Active == false. Should it be untouched? That would make NHibernate store a state which doesn't represent your domain object.