I am trying to set a default value for an UUID type field
/**
* #var int
*
* #ORM\Column(name="uuid", type="guid", options={"default"="uuid_generate_v4()"})
* #ORM\Id()
* #ORM\GeneratedValue(strategy="UUID")
*/
private $uuid;
However this sets executes
ALTER TABLE store ALTER uuid SET DEFAULT 'uuid_generate_v4()';
and takes it as text. How do I define a DB function as default in doctrine annotations?
On creation table you can use this annotation
/**
* #ORM\Column(name="uuid", type="guid", columnDefinition="DEFAULT uuid_generate_v4()", options={"comment"="Column Comment Here"})
* #ORM\Id()
* #ORM\GeneratedValue(strategy="UUID")
*/
private $uuid;
The ColumnDefinition append the content to DDL see Doctrine Documentation
The SQL output for this config is
ALTER TABLE table_name ADD uuid DEFAULT uuid_generate_v4();
COMMENT ON COLUMN table_name.uuid IS 'Column Comment Here';
These annotation does nothing on CHANGE COLUMN. Only works on ADD COLUMN generated SQL. You must recreate the column or change your table by hand.
IMPORTANT NOTE:
For those that looking for create UUID Column Type in PostgreSQL, keep in mind that you need to enable some Extension to use functions that create uuid-hashes.
In the example, uuid_generate_v4() is derived from UUID-OSSP and older versions of PostgreSQL don't support it.
Instead UUID-OSSP you can use gen_random_uuid() function from PGCRYPTO. The UUID resultant is the same version (v4). Again, older versions doesn't support it.
Just remember to Install the Extension with Create Extension.
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; // OR
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
ANOTHER IMPORTANT NOTE: In some PostgreSQL installations (like CentOS), extensions are not included by default. You must install them.
For CentOS/RHEL you need to install postgresql-contrib. Pay attention to the version of your PostgreSQL. I.e. for version 9.5 you must use postgresql95-contrib
My Privileges are weak
There's a trick to create uuid hashes without extensions. Just use the instruction above.
uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);
If your version suport ::UUID casting, use
md5(random()::text || clock_timestamp()::text)::uuid
Related
Currently the top answer for How does a Django UUIDField generate a UUID in Postgresql? says
When you use UUIDField as a primary key in Django, it doesn't generate a UUID one for you, you generate it yourself before you save the object
But I think it should be possible to hack a solution that allows for DB-based UUID generation.
Once you have installed uuid-ossp extension in postgres
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
I think it should work more or less like an AutoField.
If a raw sql has been used for the table creation
CREATE TABLE example(
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
);
Then raw insert will return a new random UUID as an id field.
How would one go about creating a custom Field so this raw solution works with Django ORM?
I just run into the solution for this question I asked a year ago. Django provides you with RandomUUID which calls gen_random_uuid in PostgreSQL.
Example usage:
from django.contrib.postgres.functions import RandomUUID
class MyModel(models.Model):
id = models.UUIDField(primary_key=True, default=RandomUUID)
Where RandomUUID is
class RandomUUID(Func):
template = 'GEN_RANDOM_UUID()'
output_field = UUIDField()
For version below 13 PostgreSQL docs mention that calling gen_random_uuid
Returns a version 4 (random) UUID. (Obsolete, this function is now also included in core PostgreSQL.)
It's obsolete as "obsolete in pgcrypto" extension.
In PostgreSQL docs for version 13 and above you can find this function being mentioned under Chapter 9. Functions and Operators
section.
This function returns a version 4 (random) UUID. This is the most commonly used type of UUID and is appropriate for most applications.
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.
In the Doctrine docs they mention that there exists a few different strategies for the #GeneratedValue annotation:
AUTO
SEQUENCE
TABLE
IDENTITY
UUID
CUSTOM
NONE
Would someone please explain the differences between all thees strategies?
Check the latest doctrine documentation
Here is a summary :
the list of possible generation strategies:
AUTO (default): Tells Doctrine to pick the strategy that is preferred by the used database platform. The preferred strategies are IDENTITY for MySQL, SQLite and MsSQL and SEQUENCE for Oracle and PostgreSQL. This strategy provides full portability.
SEQUENCE: Tells Doctrine to use a database sequence for ID generation. This strategy does currently not provide full portability. Sequences are supported by Oracle and PostgreSql and SQL Anywhere.
IDENTITY: Tells Doctrine to use special identity columns in the database that generate a value on insertion of a row. This strategy does currently not provide full portability and is supported by the following platforms:
MySQL/SQLite/SQL Anywhere => AUTO_INCREMENT
MSSQL => IDENTITY
PostgreSQL => SERIAL
TABLE: Tells Doctrine to use a separate table for ID generation. This strategy provides full portability. This strategy is not yet implemented!
NONE: Tells Doctrine that the identifiers are assigned, and thus generated, by your code. The assignment must take place before a new entity is passed to EntityManager#persist. NONE is the same as leaving off the #GeneratedValue entirely.
SINCE VERSION 2.3 :
UUID: Tells Doctrine to use the built-in Universally Unique Identifier generator. This strategy provides full portability.
Ofcourse the accepted answer is correct, but it needs a minor update as follows:
According to Annotation section of the documentation:
This annotation is optional and only has meaning when used in conjunction with #Id.
If this annotation is not specified with #Id the NONE strategy is used as default.
The strategy attribute is optional.
According to Basic Mapping section of the documentation:
SEQUENCE: Tells Doctrine to use a database sequence for ID generation. This strategy does currently not provide full portability. Sequences are supported by Oracle, PostgreSql and SQL Anywhere.
IDENTITY: Tells Doctrine to use special identity columns in the database that generate a value on insertion of a row. This strategy does currently not provide full portability and is supported by the following platforms:
MySQL/SQLite/SQL Anywhere (AUTO_INCREMENT)
MSSQL (IDENTITY)
PostgreSQL (SERIAL).
Downvote
Regarding the downvote given by someone, it should be noted that SQL Anywhere has been added and the accepted answer needs a minor update.
From the perspective of a programmer, they all achieve the same result: that is to provide a UNIQUE value for the primary key field. Strictly speaking, there are two further conditions which are also met, namely: the key must also be mandatory and not null.
The only differences lie in the internal implementations which provide the primary key value. In addition, there are performance and database-compatibility factors which also need to be considered. Different databases support different strategies.
The easiest one to understand is SEQUENCE and this is generally also the one which yields the best performance advantage. Here, the database maintains an internal sequence whose nextval is accessed by an additional SQL call as illustrated below:
SELECT nextval ('hibernate_sequence')
The next value is allocated during insertion of each new row. Despite the additional SQL call, there is negligible performance impact. With SEQUENCE, it is possible to specify the initial value (default is 1) and also the allocation size (default=50) using the #SequenceGenerator annotation:
#SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
The IDENTITY strategy relies on the database to generate the primary key by maintaining an additional column in the table whose next value is automatically generated whenever a new row is inserted. A separate identity generator is required for each type hierarchy.
The TABLE strategy relies on a separate table to store and update the sequence with each new row insertion. It uses pessimistic locks to maintain the sequence and as a result is the slowest strategy of all these options. It may be worth noting that an #TableGenerator annotation can be used to specify generator name, table name and schema for this strategy:
#TableGenerator(name="book_generator", table="id_generator", schema="bookstore")
With the UUID option, the persistence provider (eg Hibernate) generates a universally unique ID of the form: '8dd5f315-9788-4d00-87bb-10eed9eff566'. To select this option, simply apply the #GeneratedValue annotation above a field declaration whose data type is UUID; eg:
#Entity
public class UUIDDemo {
#Id
#GeneratedValue
private UUID uuid;
// ...
}
Finally, the AUTO strategy is the default and with this option, the persistence provider selects the optimal strategy for the database being used.
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 can I add a CHECK .. IN constraint, like in the code below, in Doctrine 2?
CREATE TABLE table_name (
colum_name VARCHAR(1)
CHECK (column_name IN ('A','B','C'))
);
-- edit: I use annotations to define my entities
This is not supported by the ORM itself. You can define custom DDL to be used for those columns through your metadata driver. For instance, in the AnnotationDriver you can use /** #Column(type="string", columnDefinition="VARCHAR(1) CHECK (column_name IN ('A','B','C'))") */ as defined in the Annotations Reference.
I would avoid it anyway and keep those checks on application level.