Using column length to validate - doctrine-orm

/**
* #Column(type="string", length=10)
*/
protected $name;
What exactly is the purpose of 'length'?
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref-column
At the above URL it states: "length: Used by the 'string' type to determine its maximum length in the database. Doctrine does not validate the length of a string values for you."
I have the length defined in my database, so what is the point of adding 'length' in Doctrine? Does 'length' have anything to do with validation?
The only thing I can figure out is it cuts off the excess characters before trying to insert it into the database. Very annoying when I want an exception or error.
Thanks :D

Doctrine does not apply any kind of validation on your entities: it just loads and saves data applying the required type conversions (and fails if something is wrong with your objects).
The length attribute is there just to aid during schema generation when you use Doctrine's schema tools.
You can still extract that value with the metadata API of Doctrine 2 ORM eventually, but consider using a proper validation library for such tasks.

Related

Updating ElasticSearch mappings field type with existing data

I'm storing a few fields and for the sake of simplicity lets call the field in question 'age'. Initially ES created the index for me and it ended up choosing the wrong field type for 'age'. It's a string type right now instead of a numeric type. I'm aware that, I should have defined the mappings myself to begin with and force the data values been sent to be consistently all strings or numeric values.
What I've right now is an index with a ton of data that uses a 'string' type for age with following values: 1, 10, 'na', etc..
Now my question is: if I were to change the mapping from string to integer, would indexing have any issues with the existing data values such as 'na' when being updated ??
I just wanted to ask first before I start creating a playground environment to test with a sample data set.
What you can update according to the doc:
new properties can be added to Object datatype fields.
new multi-fields can be added to existing fields.
doc_values can be disabled, but not enabled.
the ignore_above parameter can be updated.
Otherwise I am afraid you will have to create a new mapping and reindex your data, see this post for example

Doctrine swap out table at runtime

Typically when you implement a entity using Doctrine you map it to a table explicitly:
<?php
/**
* #Entity
* #Table(name="message")
*/
class Message
{
//...
}
Or you reply on doctrine to implicitly map your class name to a table...I have several tables which are identical in schema but I do not wish to re-create the class for each time...there fore at runtime (dynamically) I would like to change the table name accordingly.
Where do I start or what would I look into overriding to implement this odd requirement???
Surprisingly (to me), the solution is very simple. All you have to do is to get the ClassMetadata of your entity and change the name of the table it maps to:
/** #var EntityManager $em */
$class = $em->getClassMetadata('Message');
$class->setPrimaryTable(['name' => 'message_23']);
You need to be careful and do not change the table name after you have loaded some entities of type Message and changed them. It's a big chance it will either produce SQL errors on saving (because of table constraints, for example), if you are lucky or it will modify the wrong row (from the new table).
I suggest the following workflow:
set the desired table name;
load some entities;
modify them at will;
save them;
detach them from the entity manager (the method EntityManager::clear() is a quick way to start over);
go back to step 1 (i.e. repeat using another table).
The step #5 (detach the entities from the entity manager) is useful even if you don't change or don't save the entities. It allows the entity manager use less memory and work faster.
This is just one of the many methods you can use to dynamically set/change the mapping. Take a look at the documentation of class ClassMetadata for the rest of them. You can find more inspiration in the documentation page of the PHP mapping.

Doctrine2 one-to-one relation auto loads on query

I have a query that looks like this:
My user entity has a one-to-one relation that looks like this:
/**
* #var UserProfile
*
* #ORM\OneToOne(targetEntity="UserProfile",mappedBy="user")
*/
private $userProfile;
Anytime I make a query to select multiple user objects, it creates an additional select statement per user to query for the UserProfile data even though I am not accessing it through a get method. I don't always need the UserProfile data, and I certainly don't want to load this data every single time I'm displaying a list of users.
Any idea why these queries are executed at run time?
Here is solutions explain with details :
https://groups.google.com/forum/#!topic/doctrine-user/fkIaKxifDqc
"fetch" in the mapping is a hint, that is, if it is possible
Doctrine does that, but if its not possible, obviously it does not.
Proxying for lazy-loading is simply not always possible, technically.
The situations where its not possible are:
1) one-to-one from inverse to owning side (appears only in
bidirectional one-to-one associations). Precondition a) above can not
be met. 2) one-to-one/many-to-one association to a hierarchy and the
targeted class has subclasses (is not a leaf in the class hierarchy).
Precondition b) above can not be met.
In these cases, proxying is technically not possible.
Your options to avoid this n+1 problem:
1) fetch-join via DQL: "select c,ca from Customer join c.cart ca".
Single query but join, however, joins on to-one associations are
relatively cheap.
2) force partial objects. No additional queries but
also no lazy-load: $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD,
true)
3) if an alternative result format (i.e. getArrayResult()) is
sufficient for a use-case, these also avoid this problem.
Benjamin had some ideas about automatic batching of these loads to
avoid n+1 queries but this does not change the fact that proxying is
not always possible.
I spent a lot of time searching for a solution. For me, none of the options were satisfying enough, but maybe I can save someone some time with this list of workarounds:
1) Change the owning side and inverse side http://developer.happyr.com/choose-owning-side-in-onetoone-relation - I don't think that's right from a DB design perspective every time.
2) In functions like find, findAll, etc, the inverse side in OneToOne is joined automatically (it's always like fetch EAGER). But in DQL, it's not working like fetch EAGER and that costs the additional queries. Possible solution is every time to join with the inverse entity
3) If an alternative result format (i.e. getArrayResult()) is sufficient for some use-cases, that could also avoid this problem.
4) Change inverse side to be OneToMany - just looks wrong, maybe could be a temporary workaround.
5) Force partial objects. No additional queries but also no lazy-loading: $query->setHint (Query::HINT_FORCE_PARTIAL_LOAD, true) - seams to me the only possible solution, but not without a price:
Partial Objects are a little bit risky, because your entity behavior is not normal. For example if you not specify in ->select() all associations that you will user you can have an error because your object will not be full, all not specifically selected associations will be null
6) Not mapping the inverse bi-directional OneToOne association and either use an explicit service or a more active record approach - https://github.com/doctrine/doctrine2/pull/970#issuecomment-38383961 - And it looks like Doctrine closed the issue
It seems that this is a open issue in Doctrine, see also
4.7.1. Why is an extra SQL query executed every time I fetch an entity with a one-to-one relation?
If Doctrine detects that you are fetching an inverse side one-to-one association it has to execute an additional query to load this object, because it cannot know if there is no such object (setting null) or if it should set a proxy and which id this proxy has.
To solve this problem currently a query has to be executed to find out this information.
Source
As #apfelbox explained... there is no fix for it now.
I went for a OneToMany solution in a combination with unique key:
User.php
/**
* #ORM\OneToMany(targetEntity="TB\UserBundle\Entity\Settings", fetch="EXTRA_LAZY", mappedBy="user", cascade={"all"})
*/
protected $settings;
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getSettings()
{
return $this->settings;
}
And
Settings.php
/**
* #ORM\ManyToOne(targetEntity="TB\UserBundle\Entity\User", fetch="EXTRA_LAZY", inversedBy="settings")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*/
protected $user;
And to ensure the uniqueness in Settings.php include:
use Doctrine\ORM\Mapping\UniqueConstraint;
And add unique index
/**
* #ORM\Entity
* #ORM\Table(name="user_settings", uniqueConstraints={#UniqueConstraint(name="user", columns={"user_id"})})
*/
class Settings
So when I want to access the user Settings I just need to this (which will fire ONE query ONLY in that specific moment)
$_settings = $user->getSettings()->current();
I think is the cleanest solution.
There is another option (which is the best IMHO) - you could use unidirectional OneToOne.
In your case - if you use UserProfile rarely - setup link in UserProfile
/**
* #var User
*
* #ORM\OneToOne(targetEntity="User")
*/
private $user;
And just dont map it in User. You could load it, when you will need it.
If you use UserProfile often - you could make it part of User entity.
According to the reference you can add the optional attribute fetch
/**
* #var UserProfile
*
* #ORM\OneToOne(targetEntity="UserProfile",mappedBy="user", fetch="LAZY")
*/
private $userProfile;

Doctrine ORM error : Unknown column type varchar requested

Ok, so i just assigned a new project which uses Doctrine and Zend. This is my first time using Doctrine, and i came upon an error for which google didn't came up with any answer.
I added a new field (VARCHAR 17) to a table, added getter/setter functions in the Entity for that table, then ran orm:generate-proxies.
All good, except now i am getting this error when trying to save anything: Unknown column type varchar requested.
Any thoughts?
The problem is, that doctrine annotation doesn't know about the underlying database. So what you have to do is mark your field as type string with length of 17 in your case:
/**
* mySuperField
* \ORM\Column(name="mySuperField", type="string", length=17)
*/
$mySuperField;
For reference about how to map entity properties see also Doctrine Basic Mapping
At first learn about doctrine commands
orm:generate-entities to write getter/setter functions in the Entity files,
orm:schema-tool:update to update db tables,
you should not do this work manually, just write yaml/xml/php schema and run them.
If you use Bisna library to integrate doctrine2 with zf, there must be "adapterClass" and "mappingDirs[]" options in application.ini file to describe where schema files are.
Use type "string" instead of varchar in entity and schema files.
I prefer yaml schemas:
username:
type: string
length: 17

How to get constraint errors from OCIErrorGet?

Our C++ program is using Oracle and OCI to do its database work. Occasionally, the user will trigger a constraint violation, which we detect and then show an error message from OCIErrorGet. OCIErrorGet returns strings like this:
ORA-02292: integrity constraint (MYSCHEMA.CC_MYCONSTRAINT) violated - child record found
ORA-06512: at line 5
I am looking for the cleanest way to extract "MYSCHEMA.CC_MYCONSTRAINT" from the Oracle error. Knowing the name of the constraint, I could show a better error message (our code could look up a very meaningful error message if it had access to the constraint name).
I could use a regex or something and assume that the Oracle message will never change, but this seems a little fragile to me. Or I could look for specific ORA codes and then grab whatever text falls between the parentheses. But I was hoping OCI had a cleaner/more robust way, if a constraint fails, to figure out the actual name of the failed constraint without resorting to hardcoded string manipulation.
Any ideas?
According to the Oracle Docs, a string search is exactly what you need to do:
Recognizing Variable Text in Messages
To help you find and fix errors, Oracle embeds object names, numbers,
and character strings in some messages. These embedded variables are
represented by string, number, or character, as appropriate. For
example:
ORA-00020: maximum number of processes (number) exceeded
The preceding message might actually appear as follows:
ORA-00020: maximum number of processes (50) exceeded
Oracle makes a big point in their docs of saying the strings will be kept up to date in their section on "Message Accuracy." It's a pretty strong suggestion that they intend you to do a string search.
Also, according to this website, the Oracle Error structure also pretty strongly implies that they intend you to do a string search, because the data structure lacks anything else for you to get:
array(4) {
["code"]=>int(942)
["message"]=>string(40) "ORA-00942: table or view does not exist"
["offset"]=>int(14)
["sqltext"]=>string(32) "select * from non_existing_table"
}
This output reveals the following information:
The variable $erris an array with four elements.
The first element is accessible by the key ‘code’ and its value is number 942.
The second value is accessible by the key ‘message’ and the value is string “ORA-00942: table or view does not exist”.
The third value is accessible by the key ‘offset’, and its value is the number 14. This is the character before the name of the
non-existing table.
The fourth member is the problematic SQL message causing the error in the first place.
I agree with you; it would be great if there were a better way to get the constraint name you're violating, but string-matching seems to be the intended way.