ZF2 Mapping ResultSet of a Join-Statement into different Objects - zend-db

when it comes down to increasing performance, reducing the amount of single SQL-Queries is one part of that.
Now let's assume a very basic example: i have a blog-table and a user-table. Each blog is referencing to a user by a given primary key.
A statement could be like
SELECT blog.title, blog.text, user.name FROM blog, user INNER JOIN on blog.user_id = user.id
Now my Blog-object i would like to have a $user-property which is a User-object
My Question: Are there inbuilt features within ZF2 to handle such a case? Or would i be needed to either manually map each field of the result into my objects?
Thanks in advance

No, there are no inbuilt features with ZF2 to do this - you should consider Doctrine 2 or Propel if you want that.
With Zend\Db however, you could write such SQL statements within your mapper class and then use an ArraySerializable hydrator to populate the blog entity. The blog entity's populate() could then choose to create a user object with the user data that is passed to it.

Related

What does Include() do in LINQ?

I tried to do a lot of research but I'm more of a db guy - so even the explanation in the MSDN doesn't make any sense to me. Can anyone please explain, and provide some examples on what Include() statement does in the term of SQL query?
Let's say for instance you want to get a list of all your customers:
var customers = context.Customers.ToList();
And let's assume that each Customer object has a reference to its set of Orders, and that each Order has references to LineItems which may also reference a Product.
As you can see, selecting a top-level object with many related entities could result in a query that needs to pull in data from many sources. As a performance measure, Include() allows you to indicate which related entities should be read from the database as part of the same query.
Using the same example, this might bring in all of the related order headers, but none of the other records:
var customersWithOrderDetail = context.Customers.Include("Orders").ToList();
As a final point since you asked for SQL, the first statement without Include() could generate a simple statement:
SELECT * FROM Customers;
The final statement which calls Include("Orders") may look like this:
SELECT *
FROM Customers JOIN Orders ON Customers.Id = Orders.CustomerId;
I just wanted to add that "Include" is part of eager loading. It is described in Entity Framework 6 tutorial by Microsoft. Here is the link:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
Excerpt from the linked page:
Here are several ways that the Entity Framework can load related data into the navigation properties of an entity:
Lazy loading. When the entity is first read, related data isn't retrieved. However, the first time you attempt to access a navigation property, the data required for that navigation property is automatically retrieved. This results in multiple queries sent to the database — one for the entity itself and one each time that related data for the entity must be retrieved. The DbContext class enables lazy loading by default.
Eager loading. When the entity is read, related data is retrieved along with it. This typically results in a single join query that retrieves all of the data that's needed. You specify eager loading by using the Include method.
Explicit loading. This is similar to lazy loading, except that you explicitly retrieve the related data in code; it doesn't happen automatically when you access a navigation property. You load related data manually by getting the object state manager entry for an entity and calling the Collection.Load method for collections or the Reference.Load method for properties that hold a single entity. (In the following example, if you wanted to load the Administrator navigation property, you'd replace Collection(x => x.Courses) with Reference(x => x.Administrator).) Typically you'd use explicit loading only when you've turned lazy loading off.
Because they don't immediately retrieve the property values, lazy loading and explicit loading are also both known as deferred loading.
Think of it as enforcing Eager-Loading in a scenario where your sub-items would otherwise be lazy-loading.
The Query EF is sending to the database will yield a larger result at first, but on access no follow-up queries will be made when accessing the included items.
On the other hand, without it, EF would execute separte queries later, when you first access the sub-items.
include() method just to include the related entities.
but what happened on sql is based on the relationship between those entities which you are going to include what the data you going to fetch.
your LINQ query decides what type of joins have to use, there could be left outer joins there could be inner join there could be right joins etc...
#Corey Adler
Remember that you should use .Include() and .ThenInclude() only when returning the object (NOT THE QUERYABLE) with the "other table property".
As a result, it should only be used when returning APIs' objects, not in your intra-application.

How to make ORM (ActiveRecord) Models for union queries in Rails

I have an application that has some basic entities
Posts
posts have:
Likes
Comments
and Ratings
I then have an SQL view to query for all three. With that I have a model called something like PostActivityView. A post has an activity view so I can call
#post.activity_view
which returns a collection of the appropriate values (from Likes, Comments, and Ratings). This all works correctly.
My issue is that this returns a collection of hashmaps, not Comments, Likes, and Ratings. This makes sense because my view is creating a new "with PostEvents as (...)" result. My question: is there a way to generalize these results and represent them with an ActiveRecord object?
Likes, Comments, and Ratings have different attributes so I do some aliasing in the view (comment's have comment.body for text and Ratings can have rating.comments for text so when needed I rename something like review.comments to .body). So my results all have the same attributes. It seems like I should be able to make an ActiveRecord object like PostEvent which just has the aliased columns. Is this possible?
I don't know how to do what you're describing. However ,do you really need to store them in separate tables? You could keep them all in a single table and use single table inheritance (http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Single+table+inheritance) to have separate classes (Likes, Comments, or Ratings) for each type of thing a particular row represents. Then the common stuff could sit up in the parent class, and the stuff specific to the more granular things could go into the descendant classes.
It sounds like your situation is the opposite of that and you're combining separate tables into a single union. I suspect that'd be very difficult to implement in ActiveRecord itself as different databases have different rules for how and when the contents of a database view may be modified (i.e., if you could somehow create an AR class that referenced your view the way you're proposing, what would happen when you call save?)
It sounds like you've gone down the path of providing a view to make it convenient to retrieve all of these objects in one set as a single type of object, when your requirement is really to bring back different objects.
Based on that I'd question the use of the view at all. I'm not anti-view you understand -- we use them quite a lot for producing read-only reports in our application for performance reasons -- but if you need the rows to be returned as their proper object type then I'd retrieve them separately as Likes, Comments, and Ratings.
First solution would be to use the gem scenic and create an activity_views view by using a union query:
create view activity_views
as (
select ...
from likes
union
select ...
from comments
union
select ...
from rating
)
your data need to be homogenous of course.

SQL call in Rails, return object that isn't defined by a model

I know how to call SQL to select data from already defined Models, like so:
Friend.find_by_sql(["...."])
My question is what do I do if I need information that isn't defined by a model?
I have a Meal table, Friend table, and Component table. Components make up Meals, and Friends can be allergic to Components. I have a SQL command (which I can't post here due to confidentiality reasons, but the implementation isn't that relevant anyway) that returns a friend_id and component_id, given a Meal. That is, it returns a list of rows (with two columns each, friend_id and component_id) telling me which Friends are allergic to which Components in a given Meal. But I don't know how to store this in a variable in Ruby and access that information.
To give some pseudocode to give you an idea of what I want to do:
#allergies_for_a_meal = ....<INSERT SQL QUERY HERE>...
#friends_who_are_allergic = Friends.find_by_id(#allergies_for_a_meal.friend_id)
Can someone give me an idea of the proper syntax for this?
If you're inside an ActiveRecord::Base subclass (such as a model) then you'll have access to the current database connection through connection; the connection has useful methods like select_rows:
a = connection.select_rows('select id from ...').map { |r| r[0].to_i }
If you're not inside a model class then you really shouldn't be directly messing with the database but you can use ActiveRecord::Base.connection if you must.
You can create a SQL View in your database, then create a read-only ActiveRecord model to read data from it.
That way:
your complex sql is stored in the dbms (and parsed only once).
you can use all of the usual ActiveRecord accessors and finders to access the data
you can add additional Find constraints to the View's SQL
Note that some Views can be written to, depending on the View's SQL, DBMS, engine, etc. But I recommend against that.

NHibernate: Returning only two properties of an entity in a Dictionary

We are using Oracle 10g database, NHibernate, WCF and Silverlight 3.0 in our project
The situation we have is that the entities in my project have many properties. But for certain situations, like showing the options in dropdown, I only want to retrieve the list of ID and Name field for that entity. I do not want to return a list of the entire entity object as a whole as there are many columns in the table. Presently I am using two SELECT queries: one to fetch the list of IDs and second to fetch the list of Names separately. Then I join these two queries and form a Dictionary and pass it to the UI.
The concern for me is that would it be possible to achieve this in a single query itself?
One approach that I know of is to create a new class having only the ID and Name property, import it into NHiberante and then form a list of this new class and send it to the UI. I want to avoid this approach for now as there are many tables for which I have to implement this functionality and hence I will have to create many new classes and corresponding xml files.
Any sort of help would be greatly appreciated.
Here is one way to do it using the Criteria API, Projections and AliasToBean. If it's a simple non-persistent class containing Id and Name you can reuse the class. NHibernate query CreateCriteria

How do I use OData Expand like a SQL join?

I'm trying to figure out how to accomplish the equivalent of:
select *
from Users u
inner join Comments c on c.UserId = u.Id
where Id = 1569
(table aliases for better sql readability)
...on the StackOverflow OData endpoint. How would this url be constructed? I'm looking at the documentation for Expand at OData.org and I would have thought it'd look something like:
https://odata.sqlazurelabs.com/OData.svc/v0.1/rp1uiewita/StackOverflow/Users?$Expand=Comments&$filter=UserId eq 1569 but isn't right.
In Linq, it would be this (I think), but Join isn't supported:
Users.Where(u=>u.Id==1569).Join(Comments, u=>u.Id, c=>c.UserId, (a,b)=>a.Id==b.UserId)
I don't need to figure this out in Linq strictly, I'm just trying to figure out how to construct the query url. Basically, how can I translate the SQL join predicate to an OData url and do this in one call?
The right way to do this would be something like:
http://odata.stackexchange.com/stackoverflow/atom/Users(1569)?$expand=Comments
The problem is that there seem to be no users in the data source (don't know why), so the above query will return a 404. But it is the right syntax.
The idea is that if you want information about just one user you "navigate" to it by using the /Users(1569) (the stuff in parethesis is the primary key of the entity set). Then if you also want to include all the comments, you simply add $expand=Comments. If you want just the comments and not the information about the user you can do /Users(1569)/Comments.
Note that the service you used doesn't define navigation properties, so the above won't work as "joins" are not really supported. But the stackexchange odata endpoint does have the navigation properties defined.
Basically the joins are defined on the server/service so that the client doesn't have to know which column is a foreign key to which primary key.
It also helps with data sources which don't use relational databases as their storage, as it doesn't force them to create fake foreign keys.
You can expand down further "layers" of the graph. If the entity returned in the expand also defines further navigation properties, then you can specify a comma-separated list of the navigation properties.
Here's an example for a made-up service, note that this is expanding each customer in the collection, which is similar to a multiple join.
.../Customers?$expand=Orders,OrderDetails