References function in rails 4 - ruby-on-rails-4

I'm just not understand the new references() function in Rails 4
I'm reading the definition here : http://apidock.com/rails/ActiveRecord/QueryMethods/references
It's meaby a english problem, but it's still not clear for me.
What is the goal of this new feature? (code was working well without it before).
Must I always add a reference for each table of my includes() ?
Thanks

When using includes, Rails will usually load the results separately. For example, if you do
Post.includes(:comments)
it will issue a query to load the post(s) and then another to load the comments with the post_id of the post(s).
It will generate a join, if, for example, you want to do
Post.includes(:comments).where(comments: { user_id: 44})
Where one of the conditions is dependent on a related table. If, however, you were to use
Post.includes(:comments).where('comments.user_id = ?', 44)
You will get an error in Rails 4. Any time that you're referencing a relationship in a conditional using a SQL snippet, you will have to use references. To fix the above, we would do
Post.includes(:comments).where('comments.user_id = ?', 44).references(:comments)
The other option, of course, is to not use SQL snippets in your conditionals, like the second code example, but it's not always possible to avoid them.

I think this is intended for when you're eager loading an association and you're using a string condition. Because Rails doesn't want to have to parse raw SQL in where clauses to figure out what you're doing, so references is intended to make it more explicit what is going on in your query.
Group.includes(:users).where('users.first_name = ?', 'John')
You should get some kind of deprecation warning if you do this. But if you use a hash syntax you should not get the deprecation warning:
Group.includes(:users).where(users: { first_name: 'John' })
So to fix the deprecation warning on the first one, you would add references(:users) to it.
Group.includes(:users).where('users.first_name = ?', 'John').references(:users)

The query method references is used to indicate that an association is referenced by a SQL string and therefore be joined over being loaded separately. As of Rails 4.1, adding a string condition of an included reference will result in an exception being raised.
Here is an example that selects all Teams which have a member named Nishant:
>> Team.includes(:members).where('members.name = ?', 'Nishant')
SQLite3::SQLException: no such column: members.name: SELECT "teams".*
FROM "teams" WHERE (members.name = 'Nishant')
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column:
members.name: SELECT "teams".* FROM "teams" WHERE (members.name =
'Nishant')
...
To get the above example to work in Rails 4.1, we must include query method references with the name of the association to join
Team.includes(:members).where("members.name = ?", 'Nishant').references(:members)
However, if you were using the hash syntax with association conditions, it would still perform a LEFT OUTER JOIN without any exception being raised:
Team.includes(:members).where(members: { name: 'Nishant' })
Note that ordering string SQL snippets on included associations will still work the same way without the need
of references:
Team.includes(:members).order('members.name')
I hope this will help you.

Related

How to use Doctrine 2 DQL ON to override default JOIN condition

For starters, it is NOT a duplicate of Doctrine 2 JOIN ON error. I am indeed getting Expected end of string, got 'ON' but using WITH won't solve my case.
The problem there is similar but different from mine. I don't need to add a condition to my JOIN, I need to substitute the default condition with a different one.
Let's say, we have 2 hypthetical tables: album and artist, with an artist_id FK pointing from album to artist. In my case, I don't want to join artists with their albums. I want to list artists joined with unrelated albums using some arbitrary condition. So each artist will be joined with the exact same small set of albums. Believe me, in my case it does make sense - I don't want to describe it fully because it is too complex and out of the scope of my question.
SELECT * FROM artist
LEFT JOIN album ON album.some_unrelated_property = 'foo'
The example above is raw SQL (I'm using PostgreSQL) and works perfectly fine in this form.
In my code I'm using query builder (hard to avoid it, because my query is way more complex and built step by step by a series of functions). The line that causes an error is this:
$qb->leftJoin('artist.albums', 'aa', Join::ON, 'aa.someUnrelatedProperty = "foo"');
In Doctrine I'm getting the dreaded Expected end of string, got 'ON'. When I use WITH instead of ON it works, but as expected, it appends the standard join condition by artist_id which I do not want.
What's even more confusing for me, in this post: What is the difference between JOIN ON and JOIN WITH in Doctrine2? which explains a difference between ON and WITH in DQL, somebody uses an example equivalent to mine as a correct use of ON in DQL:
Case Two
DQL
FROM Album a LEFT JOIN a.Track t ON t.status = 1
Will translate in SQL
FROM Album a LEFT JOIN Track t ON t.status = 1
What am I missing here? Is it possible to achieve what I want at all, using DQL? If not, what the hell is the reason for ON to exist in DQL when there's also WITH which works in more standard cases?

Doctrine ORM "Multiple non-persisted new entities were found through the given association graph:"

$added_obj = [];
foreach ($something as $data) {
$obj = $this->class->function($data, $par2);
if (null !== $obj && !(array_key_exists
(->getVal1(), $added_obj[$obj->getVal1()] === $$obj->getVal2())) {
$this->persister->persist($obj);
$added_bank_account[$obj->getVal1()] = $obj->getVal2();
} else {
}
}
What the code does: It calls an function which returns an entity or null. If an entity was created there is an check if 2 values already exists in an array, if not, than persist and add the 2 values to an array as key/val pair.
But, when an entity is created and it already exists in the array i don't want it to be persisted, but I want to do nothing with it.
But, when I do absolutely zero with it I got the error:
```Multiple non-persisted new entities were found through the given association graph:
A new entity was found through the relationship 'MyCompany\Client\Entity\Client#something' that was not configured to cascade persist operations for entity:
which makes sense because doctrine doesn't know what to do with the created entity. How can I "destroy" the created entity so that the problem is solved.
When there is only 1 object created everything works fine.
In your case you can simply merge or clear the entity from EntityManager
ex :
$em->merge($obj);
OR
$em->clear($obj);
I was facing the same issue because it was trying to insert a duplicated registry in a particular table, when in fact I was just trying to update it.
I was doing a persist with a flush right after.
So I found that (obvious for many, but certainly helpful):
->merge
will duplicate the registry in many cases, if the id is not set properly.
If you are trying to update an entity, this is not a good idea.
->persist
In the same way, if you are trying to update an entity, you may not use it. It's used to add a new entity to the db. To update a record, you may just use flush as you can see in this example from the docs.
I had the same problem and googling this error did not give me much results, but it appeared that in case of only one entity (not multiple) doctrine gives different error message, which has a solution that worked for multiple entities too. So, let me leave here a link for it: Doctrine - A new entity was found through the relationship
This problem occurs if you got the related entity in another object manager. For example, if there was previously a check for duplication through an exception and resetting the manager.

Why doesn't the parameter index work?

In the documentation, https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/
it uses {0} to reference the parameter 'movieTitle'.
#Query("MATCH (movie:Movie {title={0}}) RETURN movie")
Movie getMovieFromTitle(String movieTitle);
However, in my own code, if I use "{title={0}", my IntelliJ always reports a syntax error. I can resolve the issue by changing it to
{title:{movieTitle}
Here I have to use the actual argument name and the colon plus {}.
Is there any trick for this? I don't think the documentation is wrong.
Question 2:
If I want the node label "Movie" to be a parameter, it also shows an error message:
#Query("MATCH (movie:{label} {title={0}}) RETURN movie")
Movie getMovieFromTitle(String movieTitle, String label);
I do not know what version of IntelliJ you are using but the first query is right. There is also a test case for this in the spring-data-neo4j project.
It is not possible to use the second query syntax because there is no support for this on the database level where the query gets executed. If it would be supported in SDN before making the call to the DB the query has to be parsed (and the pattern replaced) every time when the query get executed and SDN will loose the possibility to parse the query once and then just add the parameter values in subsequent calls. This will lower the performance of executing annotated query functions.

Drupal 8: Altering Search API queries

I'm working on a project which includes the following activated modules:
Drupal core 8.2.3
Database Search 8.x-1.0-beta4
Search API 8.x-1.0-beta4
Search API Term Handlers 8.x-1.0-beta4
Views 8.2.3
I have a list of nids which need to be excluded from the search result of the site-wide search. The search uses Search API and has been setup using Views.
The table in the database is: "search_api_db_default_index"
The field I wish to target is: "nid"
I wasn't able to get HOOK__search_api_query_alter or HOOK_search_api_results_alter to fire, so I am attempting to manipulate the query through HOOK_views_query_alter.
I have attempted to use both the "addWhere" and "addCondition" methods with the following syntax:
When using the addCondition method, I attempted
$query->addCondition('search_api_db_default_index.nid', $oneBadNid, '<>');
and
$query->addCondition('search_api_db_default_index.nid', $manyBadNids, 'NOT IN');
and when using the addWhere method, I attempted
$query->addWhere('AND', 'search_api_index_default_index.nid', $oneBadNid, '<>');
and
$query->addWhere('AND', 'search_api_index_default_index.nid', $manyBadNids, 'NOT IN');
Regardless of whether or not I prefix the field with the table name, searching always results in triggering the following notice:
Unknown field in filter clause: 'search_api_db_default_index.nid' .
It seems that the field name is always wrapped in an html encoded string representing a single quotation, but this occurs both when using double quotations or single quotations around the supplied table.field parameter.
I am not even sure that this is what is keeping me from altering my query, but it is the only thing close to an error which I have discovered in this process. It's also possible that I'm simply not supposed to be targeting the table in the manner written, but I did not find any documentation directing me to the proper methodology.
I would appreciate any insight into this issue! Thanks!
Generally you can use
$fields = $query->getIndex()->getFields();
on the query to get an array of fields you can use within the search_api query.
Piggy-backing off of Nebel54's comment, and attempting this on my own, you don't need to include the 'table' name when setting the addCondition. However, I did need to use hook_search_api_query_alter over a views-specific one.
function mymodule_search_api_query_alter(\Drupal\search_api\Query\QueryInterface &$query) {
// Ensure field_myfield is being indexed
$fields = $query->getIndex()->getFields();
if (isset($fields['field_myfield'])) {
$query->addCondition('field_myfield', 'myvalue', '<>');
}
}

merge in doctrine 2 not working giving error

I am trying to update a row in a table. I am using doctrine 2 ORM. I am trying to update a row using merge(), which is said can be used to update a row. But it gives a error saying
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
I am new to doctrine 2. please suggest what can i do?
When to merge
First off: You only need $em->merge() when you have an entity that isn't managed by the EntityManager, but you want it to be. A common use-case is when you have a serialized entity, and want the EntityManager to start managing it.
So merging entities is not directly related to updating entities in the database.
If you simply find (using $repo->find*()) an entity and make changes, calling $em-flush() is sufficient. The entity is already managed by the EntityManager and there's no need to merge it.
How to merge
A common mistake when using $em->merge() is that the passed entity itself becomes managed. This isn't true, $em->merge() returns a new object that represents the managed entity.
$managedEntity = $em->merge($detachedEntity);
After this line of code, $detachedEntity is still detached (meaning it still isn't managed by the EntityManager). It's $managedEntity which you can start using to make changes.
Your code
Given the code you've put in the comments, you probably want to do something like this:
$user = $entityManager->getRepository('User')->find($_REQUEST['id']);
$user->setName($_REQUEST['name']);
$user->setPassword($_REQUEST['pass']);
$entityManager->flush();
PS: It looks like you're saving the the plain-text password in the database. That's never a good idea.