教义中的默认值


338

如何在Doctrine 2中设置默认值?


26
@ORM \ Column(name =“ foo”,type =“ decimal”,precision = 7,scale = 2,options = {“ default” = 0})有效(来自以下非受欢迎的答案)
WayFarer

2
@ORM \ Column(name =“ is_activated”,type =“ boolean”,options = {“默认”:0})或@ORM \ Column(name =“ is_activated”,type =“ boolean”,options = {“ default “ = 0})
艾哈迈德·哈米迪(Ahmed hamdy

Ahmed在Symfony 2.3中似乎不适用于布尔值。但是options = {“ default” =“ 0”})确实有效,将整数放在引号中。
Acyra 2014年

4
如果是布尔值,为什么不使用:options = {“” default“:false}?
robocoder

Answers:


385

数据库默认值不“便携式”支持。使用数据库默认值的唯一方法是通过columnDefinitionmapping属性,在该属性中为字段所映射的列指定SQL代码段(DEFAULT包括原因在内)。

您可以使用:

<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}

首选PHP级别的默认值,因为这些值也可以在新创建和持久保存的对象上正确使用(持久保存新对象以获取默认值后,Doctrine不会返回数据库)。


11
但是这里有一个问题:如果设置“日期时间”类型怎么办?
artragis 2012年

46
@artragis将您的实例化为实体构造函数
Alain Tiemblo

16
使用这种方法进行迁移时必须格外小心,因为任何现有行都将导致迁移失败。
Tamlyn)

7
不要使用实例化区域来设置变量...相信我,不好的事情会发生。请改用构造函数区域。
mimoralea 2014年

4
我建议在注解中使用columnDefinition,否则有人将使用mysql客户端或phpmyadmin,并且值将是错误的……
NDM 2015年

541
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @ORM\Column(name="myColumn", type="integer", options={"default" : 0})
     */
    private $myColumn;
    ...
}

请注意,这使用SQL DEFAULT,某些字段(例如BLOB和)不支持SQL TEXT


4
接得好!官方文档中似乎没有options = {“ default” = 0}选项
WayFarer

2
仅供参考,options参数对于unsigned值也很有用。看到这个答案
yvoyer

5
我用这个和公认的答案来覆盖所有基础。还只是一张纸条,你也可以这样做:options={"default": 0}小心使用“,而不是”,因为这会导致我的版本学说的错误。
斯科特弗莱克

28
这应该是选定的答案!
Acelasi Eu

2
@Matt他可能说过,因为它是一个未记录的功能,并且未保留的功能很容易被删除。正如现在所记录的那样,您应该放心使用它。
JCM 2015年

62

在您的实体中设置构造函数,并在其中设置默认值。


当然,这似乎是合乎逻辑的方法。有没有人遇到在构造函数中设置默认值的问题?
cantera


@ cantera25应该是答案+1
Phill

3
如果您添加需要具有默认值的新字段,则不会更新现有实体。因此,那不应该是答案。取决于正是你需要做什么
托马什Tibenský

它也不会在更新目的上起作用。不幸的是,如果只想清空字段(即使是整数),就可以返回默认值,它将无法正常工作。
ThEBiShOp


51

更新资料

阅读 Symfony 文档的另一个原因永远不会过时。对于我的具体情况,有一个简单的解决方案,就是将field type选项empty_data设置为默认值。

同样,此解决方案仅适用于表单中的空输入将DB字段设置为null的情况。

背景

先前的答案都没有帮助我解决我的特定情况,但我找到了解决方案。

我有一个表单字段,需要执行以下操作:

  1. 不需要,可以留空。(使用'required'=> false)
  2. 如果留为空白,则应默认为给定值。为了获得更好的用户体验,我没有在输入字段上设置默认值,而是使用了html属性“ placeholder”,因为它不那么引人注目。

然后,我尝试了此处给出的所有建议。让我列出它们:

  • 为实体属性设置默认值:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • 使用选项注释:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • 在构造函数上设置默认值:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}
由于Symfony如何使用Entity类,所有这些都不起作用。

重要

Symfony表单字段会覆盖在Entity类上设置的默认值。 这意味着,可以为数据库的模式定义一个默认值,但是如果在提交表单时将非必需字段留空,则方法form->handleRequest()内部form->isValid()将覆盖Entity类上的默认值并将其设置为输入字段值。如果输入字段值为空白,则它将Entity属性设置为null

http://symfony.com/doc/current/book/forms.html#handling-form-submissions

我的解决方法

form->handleRequest()在您的form->isValid()方法内部之后,在控制器上设置默认值:

...
if ($myEntity->getMyColumn() === null) {
    $myEntity->setMyColumn('myDefaultValue');
}
...

这不是一个漂亮的解决方案,但可以。我可能会提出,validation group但可能有些人将这个问题视为数据转换而不是数据验证,我让您自己决定。


覆盖设置器(不起作用)

我还尝试通过Entity这种方式覆盖设置器:

...
/**
 * Set myColumn
 *
 * @param string $myColumn
 *
 * @return myEntity
 */
public function setMyColumn($myColumn)
{
    $this->myColumn = ($myColumn === null || $myColumn === '') ? 'myDefaultValue' : $myColumn;

    return $this;
}
...

即使看起来更干净,它也不起作用。原因是邪恶的form->handleRequest()方法没有使用模型的setter方法来更新数据(深入form->setData()了解更多细节)。


此答案应该肯定会到达顶部。表单组件使用PropertyAccessor来获取和设置属性值。也许属性访问器应在可用时使用这些方法?
Xobb 2014年

1
布尔列不支持php的默认设置,因此仅注释
Crusader

当信息来自表单时,这是唯一有效的解决方案。我也不同意以上关于布尔的评论。他们不接受默认注释。
伯纳德A'1

Symfony表单组件使用模型设置器,但仅当表单的模型格式数据与模型对象实例的相应getter返回的数据不同时才使用。如果您具有自定义的setter / getter方法-使用“ property_path”表单选项(将由PropertyAccessor处理)或自定义DataMapper(允许手动定义表单和模型对象之间的数据传输例程)。
Arkemlar

1
这个问题是关于学说的,而不是关于symfony的,因此,这个答案并不是真正的话题。
Omn

18

我使用的解决方法是LifeCycleCallback。例如,仍在等待查看是否还有其他“本机”方法@Column(type="string", default="hello default value")

/**
 * @Entity @Table(name="posts") @HasLifeCycleCallbacks
 */
class Post implements Node, \Zend_Acl_Resource_Interface {

...

/**
 * @PrePersist
 */
function onPrePersist() {
    // set default date
    $this->dtPosted = date('Y-m-d H:m:s');
}

1
对于将来的读者,不要依赖生命周期回调:)即使Marco Pivetta也反对它们。
emix

警告!如果实体已经设置了dtPosted属性,那么您的代码将简单地覆盖该属性。如果存在访问器,请始终使用它们!if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
巴尔

13

您也可以使用xml来做到这一点:

<field name="acmeOne" type="string" column="acmeOne" length="36">
    <options>
        <option name="comment">Your SQL field comment goes here.</option>
        <option name="default">Default Value</option>
    </options>
</field>

8

这是我为自己解决的方法。以下是MySQL默认值的Entity示例。但是,这还需要在您的实体中设置构造函数,并在其中设置默认值。

Entity\Example:
  type: entity
  table: example
  fields:
    id:
      type: integer
      id: true
      generator:
        strategy: AUTO
    label:
      type: string
      columnDefinition: varchar(255) NOT NULL DEFAULT 'default_value' COMMENT 'This is column comment'

在我的配置中使用这一行,Doctrine会在每次运行时尝试在列上删除默认值。php app / console准则:schema:update
shapeshifter

1
这是最糟糕的答案。columnDefinition直接使用ORM的目的是从数据库中抽象出来的。该解决方案将破坏可移植性,使您的软件依赖于数据库供应商,还将破坏Doctrine Migrations工具。
Pedro Cordeiro 2014年

@PedroCordeiro我完全同意你的看法。在出现另一个问题之前,这只是一个快速的解决方案。
Putna

7

也可以在mysql数据库上为我工作:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: integer
            nullable: true
            options:
                default: 1

采用感兴趣的注释格式:@ORM \ Column(name =“ Entity_name”,type =“ integer”,options = {“ default” =“ 1”})
汉尼斯(Hannes

7

这些都不适合我。我在主义网站上找到了一些文档,说要直接设置该值以设置默认值。

https://www.doctrine-project.org/projects/doctrine-orm/zh/2.6/reference/faq.html#how-can-i-add-default-values-to-a-column

private $default = 0;

这插入了我想要的值。


请更改链接到doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/…参见第3.2.2点。如何将默认值添加到列?
托比


3

添加到@romanb辉煌的答案。

这会增加迁移的开销,因为您显然无法创建具有非null约束且没有默认值的字段。

// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql");

//lets add property without not null contraint        
$this->addSql("ALTER TABLE tablename ADD property BOOLEAN");

//get the default value for property       
$object = new Object();
$defaultValue = $menuItem->getProperty() ? "true":"false";

$this->addSql("UPDATE tablename SET property = {$defaultValue}");

//not you can add constraint
$this->addSql("ALTER TABLE tablename ALTER property SET NOT NULL");

有了这个答案,我建议您考虑一下为什么首先需要数据库中的默认值?通常,它允许创建不具有null约束的对象。


3

如果您为实体使用yaml定义,则以下内容在PostgreSQL数据库上对我有用:

Entity\Entity_name:
    type: entity
    table: table_name
    fields: 
        field_name:
            type: boolean
            nullable: false
            options:
                default: false

1
如果$entity->setFieldName()冲洗前不使用怎么办?教义似乎将默认值定义为null。在YAML唯一的解决办法是定义默认值IN,因为它是在YAML已经定义这似乎愚蠢到我的实体类... -_-
j0k

1

我也遇到同样的问题。我想将数据库的默认值(自动)添加到实体中。猜猜是什么,我做到了:)

<?php
/**
 * Created by JetBrains PhpStorm.
 * User: Steffen
 * Date: 27-6-13
 * Time: 15:36
 * To change this template use File | Settings | File Templates.
 */

require_once 'bootstrap.php';

$em->getConfiguration()->setMetadataDriverImpl(
    new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
        $em->getConnection()->getSchemaManager()
    )
);

$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($em->getConnection()->getSchemaManager());
$driver->setNamespace('Models\\');

$em->getConfiguration()->setMetadataDriverImpl($driver);

$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
$cmf->setEntityManager($em);
$metadata = $cmf->getAllMetadata();

// Little hack to have default values for your entities...
foreach ($metadata as $k => $t)
{
    foreach ($t->getFieldNames() as $fieldName)
    {
        $correctFieldName = \Doctrine\Common\Util\Inflector::tableize($fieldName);

        $columns = $tan = $em->getConnection()->getSchemaManager()->listTableColumns($t->getTableName());
        foreach ($columns as $column)
        {
            if ($column->getName() == $correctFieldName)
            {
                // We skip DateTime, because this needs to be a DateTime object.
                if ($column->getType() != 'DateTime')
                {
                    $metadata[$k]->fieldMappings[$fieldName]['default'] = $column->getDefault();
                }
                break;
            }
        }
    }
}

// GENERATE PHP ENTITIES!
$entityGenerator = new \Doctrine\ORM\Tools\EntityGenerator();
$entityGenerator->setGenerateAnnotations(true);
$entityGenerator->setGenerateStubMethods(true);
$entityGenerator->setRegenerateEntityIfExists(true);
$entityGenerator->setUpdateEntityIfExists(false);
$entityGenerator->generate($metadata, __DIR__);

echo "Entities created";

3
几年后再回到这一点,我建议您不要使用这种方法,这确实是一个hacky hack。
Steffen Brem

由于您不建议自己回答,因此最好将其删除;)
Dragos

1

尽管在构造函数中设置该值可以工作,但使用Doctrine Lifecycle事件可能是更好的解决方案。

通过利用prePersist生命周期事件,您可以仅在初始持久化时在实体上设置默认值。


使用生命周期事件被认为是一个hack。永远不要依赖黑客。
emix

0

在属性定义上设置默认值时要小心!而是在构造函数中执行此操作,以使其保持无问题。如果在属性定义上定义它,然后将对象持久保存到数据库,然后进行部分加载,则未加载的属性将再次具有默认值。如果要再次保留该对象,则很危险。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.