I have two tables with a one (Articles) to many (Details) relationship. Details may not contain any data for the particular Article entry.
Articles: Id, Title, Numb (PK), Name
Details: Id (PK), Person, Numb (FK), Name
In the Entity Framework, there are the appropriate Navigation properties and it shows the correct One:Many relationship.
What I want to do is get all Articles that match the end user's query (by 'Name') as well as all, if any, data from the Details table (Id, Person, Numb, Name).
What I'm stuck on is right now I can query Articles just fine (var article = db.Articles.Where(b => b.Name.Equals(name));), but while the result does include a HashSet for Details.Numb on each row of Articles, there is no data in that HashSet. There are appropriate corresponding entries in the database for Article.Numb => Details.Numb.
Actually there is two ways to achieve this.
Enable Lazy Loading.
Call Include method as other answers says.
Using Lazy Loading see msdn article for more detail.
db.ContextOptions.LazyLoadingEnabled = true;
Using Include method
var article = db.db.Articles.Include("Details").Where(b => b.Name.Equals(name))).FirstOrDefault();
You need to tell EF to include the details in the result set after the query is executed (and connection closes):
var article = db.Articles
.Include("Details")
.Where(b => b.Name.Equals(name))
.FirstOrDefault();
Use .Include() on the navigation property, it will bring the entire inner object in the query result. It's only automatic if you filter or select items from the inner object, otherwise you have to manually request an include.
Example:
var allProducts = _db.Products.Include(d => d.Producer).ToList();
Always go with Include instead of lazy loading if you're not sure.
Related
I have an issue with next scheme, I attached it.I want to query from my database with only one object with "Manufacturer" class. Like:
var res = new XPQuery<Manufacturer>(session);
And then query all info that are related to my condition in LINQ.
I have tried XPLiteObject, XPObject, Association attribute, NoForeignKey Attribute, XPOCollection and a lot of stuff but nothing didn't help me.
I have tried a lot of approaches and every time I have new exception like:
SelectMany - method is not supported.
Can't set foreign key in table.
Duplicate primary key.
My question is: how to describe classes for normal extraction data from db?
UPD:
My solution now is: to use .ToList() at every object
and then use linq-query for join data and make needed query.
var manufacturer = new XPQuery<Manufacturer>(session).ToList();
var cars = new XPQuery<Car>(session).ToList();
var countries = new XPQuery<Country>(session).ToList();
var result = from m in manufacturer ....
So, I have found a solution to my question.
I downloaded DevExpress that can add templates for visual studio.
Then I select Add new item to my project named "DevExpress ORM DataModel Wizard".
This wizard can create persistent objects for existing database.
After that I can query database with next syntax:
var manufacturer = new XPQuery<Manufacturer>(session).Select(x => x....)...;
But if you want to use .SelectMany() in your LINQ query you should use .ToList() and then use .SelectMany(). I faced with a lot of issues when I have tried to join or perform some other LINQ related operations. Well, if you got some errors, firstly after .Select() try .ToList() and then perform your operation.
My database structure is this: an OptiUser belongs to multiple UserGroups through the IdentityMap table, which is a matching table (many to many) with some additional properties attached to it. Each UserGroup has multiple OptiDashboards.
I have a GUID string which identifies a particular user (wlid in this code). I want to get an IEnumerable of all of the OptiDashboards for the user identified by wlid.
Which of these two Linq-to-Entities queries is the most efficient? Do they run the same way on the back-end?
Also, can I shorten option 2's Include statements to just .Include("IdentityMaps.UserGroup.OptiDashboards")?
using (OptiEntities db = new OptiEntities())
{
// option 1
IEnumerable<OptiDashboard> dashboards = db.OptiDashboards
.Where(d => d.UserGroups
.Any(u => u.IdentityMaps
.Any(i => i.OptiUser.WinLiveIDToken == wlid)));
// option 2
OptiUser user = db.OptiUsers
.Include("IdentityMaps")
.Include("IdentityMaps.UserGroup")
.Include("IdentityMaps.UserGroup.OptiDashboards")
.Where(r => r.WinLiveIDToken == wlid).FirstOrDefault();
// then I would get the dashboards through user.IdentityMaps.UserGroup.OptiDashboards
// (through foreach loops...)
}
You may be misunderstanding what the Include function actually does. Option 1 is purely a query syntax which has no effect on what is returned by the entity framework. Option 2, with the Include function instructs the entity framework to Eagerly Fetch the related rows from the database when returns the results of the query.
So option 1 will result in some joins, but the "select" part of the query will be restricted to the OptiDashboards table.
Option 2 will result in joins as well, but in this case it will be returning the results from all the included tables, which obviously is going to introduce more of a performance hit. But at the same time, the results will include all the related entities you need, avoiding the [possible] need for more round-trips to the database.
I think the Include will render as joins an you will the able to access the data from those tables in you user object (Eager Loading the properties).
The Any query will render as exists and not load the user object with info from the other tables.
For best performance if you don't need the additional info use the Any query
As has already been pointed out, the first option would almost certainly perform better, simply because it would be retrieving less information. Besides that, I wanted to point out that you could also write the query this way:
var dashboards =
from u in db.OptiUsers where u.WinLiveIDToken == wlid
from im in u.IdentityMaps
from d in im.UserGroup.OptiDashboards
select d;
I would expect the above to perform similarly to the first option, but you may (or may not) prefer the above form.
This is a spin off from another question I posted a few days ago that was successfully answered but it really didn't get into the underlying issue I was having but wasn't able to express fully in my original query.
I have a table Product. Product is related to ProductDescription in a one-to-many relationship. ProductDescription can have more than one row for each product. It will have multiple rows if there are multiple translations for the description of the product. Product has a many-to-one relationship with Language. Language has a language code (en, es, etc.) as well as a LanguageId (found in ProductDescription as well).
I want to give my users the ability to request a product and further tell the application to only return descriptions for that product in a specific language.
The problem I'm having is that I understand I need to use projection to accomplish the task in the 3rd paragraph of this question. Something like this:
var query = inventoryRepository.Products
.Where(wherePredicate)
.Select( a=> new Product
{
ProductDescriptions = inventoryRepository.ObjectContext.ProductDescriptions
.Where(a => a.Languages.AlternateCode.Equals("en", StringComparison.CurrentCultureIgnoreCase))
});
However I have about 15 properties in the Products table as well as 4 other child tables of Products that need to be loaded for the result set in addition to just the languages piece. Is there any way for me to do eager loading AND projection so that I don't have to go through and map all of these properties and children objects manually? Here is where my code stands right now:
var query = inventoryRepository.ObjectSet
.Include("ProductDescriptions")
.Include("ProductAllowedWarehouses")
.Include("ProductToCategories")
.Include("PriceLevels")
.Include("AttachmentAssociations.Attachment").AsExpandable()
.Where(wherePredicate);
No Select necessary which is really nice. Once I change ProductDescriptions to a projection I add a Select and then I don't get any of the other properties / children populated for free.
I would read this blog about projections+eager loading. You are going to run into issues when it comes to the eager loading. Recommendation is to use a .Any and perform a sub select.
Why can't you just add a filter/where on ProductDescriptions?
var query = inventoryRepository.ObjectSet
.Include("ProductDescriptions")
.Include("ProductAllowedWarehouses")
.Include("ProductToCategories")
.Include("PriceLevels")
.Include("AttachmentAssociations.Attachment").AsExpandable()
.Where(wherePredicate)
.Where(a=>a.ProductDescriptions.Languages.AlternateCode.Equals("en", StringComparison.CurrentCultureIgnoreCase);
The following code gives me an SqlException: Invalid object name 'dbo.studentsCourses'
OO theCourse = subject.Course;
var students = dc.studentsCourses.Where(x => x.course == theCourse).Select(x => x.student);
I tried the following code instead but I also get an Exception.
My original question was asked on Aardvark and can be read bellow:
var allStudents = from s in dc.students select s;
List thestudents = new List();
foreach (student s in allStudents)
{
if (s.courses.Contains(theCourse))
{
thestudents.Add(s);
}
}
I did a right click, "run custom tool" on my dbml and checked my names of my tables and entities. The project compiles but I get an Exception at runtime on this line:
"if (s.courses.Contains(theCourse))"
Any ideas?
Original question on Aardvark:
How do I do a LinqToSQL query that
gives me this: I want to select all
students that attended a certain
lesson. The lesson is from a certain
course. So select the course the
lesson is from. Now select all the
students that are following that
course. There is a many-to-many
relationship between the students and
the courses table in my DB. I already
extended my LINQ entities to be able
to select student.Courses and
course.Students using this method:
http://www.codeproject.com/KB/linq/linq-to-sql-many-to-many.aspx
Your link to sql classes don't match your db schema or your db does not contain a table or view called studentcourses. You need to adjust either your classes or db so they match.
You could start debugging this problem by visualizing the query that is generated by the LinqToSQL. The Gu has written a blogpost on this a while ago:
http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx
Just copy/paste the query in your favourite database management application and run it against the database. It should become clear what the error is. If there are still some crazy things happening, just update your question?
Hope this helps!
First check your database to see if there is really a table or view name studentsCourses.
If there is then try to regenerate to dbml file and then try again.
I'm not sure... but you may try this one:
var xxx = dc.Include("studentsCourses")
.studentsCourses
.Where(x => x.course == theCourse)
.Select(x => x.student)
.ToList();
Let's say I have two tables:
Report
Comment
And assuming I have a database context:
var reports = db.Reports();
How can I make sure all Comments for each report are loaded as well?
At this point I want to disconnect from the database but still
have access to the comments. (For example:)
reports[0].Comments[0].Subject
I'm assuming that there is an 1-M FK relationship between reports and comments (1 Report can have many Comments)?
One option is to use the DataLoadOptions.LoadWith method - something like the following:
var reports = db.Reports();
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Reports>(r => r.Comments); // Ask for Comments along with reports
reports.LoadOptions = dlo;
Now, every time you select a report on that data context, the comments will be fetched from the db along with it.
Just beware that ALL fields from comments will be selected - there is no way using this method to select a subset of fields.
Another option is to be specific about what you want to select in the Linq query, e.g.
var myReportsList = from report in db.Reports
select new { // Using anonymous type, but could use a custom class
Report = report,
Comment = report.Comment.Detail, // for example
Subject = report.Comment.Subject
};
To understand when the query gets run and the database connection closed, you will need to understand:
The deferred execution model of Linq and Linq To Sql (Basically, for Linq to SQL, the query only runs when the results are asked for e.g. by iterating over the collection or binding to a grid)
The difference between IQueryable and IEnumerable
Jon Skeets "C# in depth" gives a great overview of these, and i've also heard very good things about "Linq in Action" - plus there are plenty of blog posts about these concepts which do the subjects more justice than I can do here ;o)
Keep in mind that if you use LoadOptions to define a multi-hop path (Reports, comments, anotherentity), the 3rd and further hops are loaded (if related over 1:n relationships) by code which is very inefficient: they'll execute one query per parent. For reports-comments, it's ok, they'll be fetched in 2 queries.