I am reading this asp.net article on building your first asp.net mvc 2 website and I came across a Linq query that uses the Include method in the query. I have used some linq, but I have never used the Include method and would like a better explanation. Does it translate to an join in linq? What is the benefit? Here is the query from the article:
var genreModel = storeDB.Genres
.Include("Albums")
.Single(g => g.Name == genre);
The article states that:
Entity Framework feature that allows us to specify other related entities we want loaded as well, called Query Result Shaping. We want to load the Albums for the matching Genre, so we'll query from Genres.Include("Albums") to indicate that we want related albums as well. This is more efficient, since it will retrieve both our Genre and Album data in a single database request.
I sort of understand what the author is saying above, but feel I would need a better example or explanation, especially since I have never used the Include method before.
If you inspect the generated sql, you'll notice that the Albums table is joined in. It should look something like:
SELECT [t0].*, [t1].*
FROM Genres [t0]
LEFT JOIN Albums [t1] ON [t0].GenreId = [t1].GenreId
WHERE [t0].Name == #p0
When the results get back to the client side, the ObjectContext will turn the row-column shape into instances of Genres and Albums. These instances will be related hierarchically - the single Genre with all of its Albums.
Suppose this genre has 5 albums. The query will return 5 rows. The object context will create one instance of Genre (each of the 5 rows has the same Genre primary key value).
Related
I have a search database of car models: "Nissan Gtr", "Huynday Elantra", "Honda Accord", etc...
Now I also have a user list and the types of cars they like
user1 likes: carId:1234, carId:5678 etc...
Given user 1 I would like to return all the cars he likes, it can be 0 to even hundreads.
What the best way to model this in Solr or potentially another "nosql" system that can help with this problem.
I'm using Solr but I have the opportunity to use another system if I can and if it makes sense.
EDIT:
Solr solution is to slow for Join (Maybe we can try nested). And the current MySQL solution which uses join tables has over 2 billion rows.
so, you just want to store a mapping between User->Cars, and retrieve the cars based on the user...sounds very simple:
Your docs are Users: contain id (indexed), etc fields
one of the field is 'carsliked', multivalued, which contains the set of car ids he likes
you have details about each care in a different collection for example.
given a user id, you retrieve the 'carsliked' field, and get the car details with a cross collection join
You could also use nested object to store each liked car (with all the info about it) inside each user, but is a bit more complex. As a plus, you don't need the join on the query.
Solr would allow you many more things, for example, given a car, which users do like it? Elasticsearch will work exactly the same way (and probably many other tools, given how simple your use case seems).
I have a generic group members table with a GUID for a "group type" and a GUID for "referenced object". An example would be if I have a table of customers(each having a GUID) I can group them under "already paid" by creating a group GUID and in my "Group members table" referencing every customer by their respective GUID. This allows for any type of group to be added to the model as we expand(without adding extra tables).
Here is the problem. I have created a subquery in an entity in order to filter the universal group members table for a certain group and what "items" are and are not in that group; like so:
partial void ElementsNotMemberOfGroup_PreprocessQuery(int? UniversalGroupTypeIDParameter, int? UniversalGroupsIDParameter, ref IQueryable<UniversalGroupMember> query)
{
query = query.Where(x => x.UniversalGroup.UniversalGroupType.UniversalGroupTypeID == UniversalGroupTypeIDParameter);
query = query.Where(x => x.UniversalGroup.UniversalGroupsID != UniversalGroupsIDParameter);
}
This returns the GUIDs for the referenced object in the group, but for a user that's useless. I need to join this table and my customers table at runtime on the GUID so I can extract the customer info and display it.
Any Ideas?
LightSwitch wasn't really created with this kind of scenario in mind. LightSwitch makes things very easy for you when you create relationships between tables that are, well, "related". When you do this, you never need manual joins between entities.
While it's possible to do something similar to what you're describing (see the link below), it's a lot more work to achieve it, and in my opinion it isn't really worth the extra trouble. Not only that, but as you're discovering, it complicates even the most simple operations.
In essence, you're working against LightSwitch, instead of with it. My advice to you would be that if you really must do this type of manual optimization, then LightSwitch may not be the best product for you to use.
Beth Massi has a blog article, Using Different Edit Screens Based on Record Types (Table Inheritance), which isn't exactly what you're doing, but it may give you some ideas if you decide to still use LightSwitch for your project.
Consider the database schema in the picture.
I need a linq-to-entities statement that will retrieve authors and their respective books grouped by author. For example, I want to display something as follows:
authorName8
bookTitle27
bookTitle35
bookTitle62
authorName37
bookTitle9
bookTitle51
An additional constraint is the oject of grouped items has to be returnable by a method.
Can anybody formulate join and group-by statement (a) ordered by author name, (b) ordered by author name and book title?
You didn't mention which version of EF you are using, or whether you need to filter the authors by some condition, or filter the books by some condition. A general query that will fetch everything will look like this:
List<Author> authorsWithBooks =
context.
Authors.
Include(a => a.Books). // For EF 4.1
/*Include("Books"). instead for previous versions of EF */
/*Where(a => !a.IsDeleted). if you want to filter the authors */
ToList();
If you want to filter the book collections, you will have to write a more elaborate query though.
var query = (from customer in MyDataContext.Aurthor select author)
.Including(author=> author.Books);
This will get you all the authors and eager load the books for best performance.
I've got a custom OData feed that for books. Each book can have multiple authors and an author can be involved in multiple books so I implemented this using a join table (Book - BookAuthorJoin - Author). My proxy object has Book.BookAuthorJoins BookAuthorJoin.Books & BookAuthorJoin.Authors.
What I want todo is have a single query where I get all the books for an author in a single LINQ query, but having trouble applying the filter. Seems I want two Expand() methods, but that isn't working. The following query doesn't work, but shows what I'm trying to do:
var query = from book in ODataContext.Books.Expand("BookAuthorJoins").Expand("Authors")
where book.BookAuthorJoins.Author.AuthorID = authorID
select book;
On the server side, the 1-to-many or many-to-many relationship is usually exposed as just a navigation property, exposing the join table in the middle will make your life much harder. If you use EF you should be able to hide the table and just expose the relationship as a navigation property.
In any case, to get all books for a certain author the query should look like:
/Authors(123)/Books
The result of this query is just a feed of books.
If you do keep the join table exposed then something like this migth work:
/Authors(123)/BookAuthorJoins?$expand=Book
But this time you get all the BookAuthorJoins with the Book for each as well.
I'm trying to implement something similar to the iTunes browser, to browser a simple database of Books. I have the following entities - Author, Genre and Book. I would like to display an author list and a genre list, which act to filter the main Book list.
I have tried doing this in 2 different ways - modeled as:
Author ( has many ) Genres ( has many ) Books
...with multiple instances of the same Genre so each author has their own for a given genre name, I have a nice drill-down hierarchy to display in my table views (albeit a bit illogical to duplicate Genres). However, when I select multiple Authors, I end up displaying dupes of the same Genre, because they are, in fact, distinct objects.
So, I tried doing it, more sensibly, with these relationships:
Author ( has many ) Books
Book ( has one ) Genre
I can get the Genre array by taking the distinct union of Genre's in the current selected Author(s) book array, but now i'm left with the problem of filtering the book list displayed based on the selected Genre(s). Because the Genre's are shared, I can't just use CurrentGenre.books, or I lose the selected Author filtering. I have noticed the 'filter predicate' field in interface builder, available on the object controllers, but am stuck working out how to actually use it to apply the selected Genre as a filter to an episode list. The apple documentation says:
"You can type a predicate directly
into the predicate editor text field
in the inspector panel of Interface
Builder or you can set it
programmatically using
setFetchPredicate:.
which gives me the impression i'm on the right track, but that's about the end of it. I'm trying to lock down the model in a nice Cocoa-esque fashion now, so as to minimize 'glue code' bits and changes later down the track. It seems like a fairly simple problem I should be able to sort out graphically in IB, but so far it's eluded me!
Thanks in advance.
I am a bit confused by your introducing "episodes" in the middle of the discussion, but I will assume you just mean "books" still.
You are definitely on the right track. You want a data model like this:
Author <-->> Book
Genre <-->> Book
Or maybe even:
Author <<-->> Book (if you support reference books, etc)
Genre <<-->> Book (if you want multi-genre support)
Once a user has selected author(s) and genre(s) you will want a Book array controller to use a filter predicate that only shows books with those author(s) or genre(s).
UPDATE
This should work:
Bind the Book array controller's filter predicate to a new predicate property "bookFilterPredicate" in your app delegate.
Add outlets for the Author and Genre array controllers.
Observe changes to the selectedObjects properties of both array controllers.
When either changes, update the filter predicate property like this: self.bookFilterPredicate = [NSPredicate predicateWithFormat:#"author IN %# && genre IN %#",authorArrayController.selectedObjects,genreArrayController.selectedObjects];