【问题标题】:Default value in DoctrineDoctrine 中的默认值
【发布时间】:2011-03-23 13:21:41
【问题描述】:

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

【问题讨论】:

  • @ORM\Column(name="foo", type="decimal", precision=7, scale=2, options={"default" = 0}) 有效(来自非流行下面回答)
  • @ORM\Column(name="is_activated", type="boolean",options={"default":0}) 或 @ORM\Column(name="is_activated", type=" boolean",options={"default"= 0})
  • Ahmed 这似乎不适用于 Symfony 2.3 中的布尔值。但是 options={"default" = "0"}) 确实有效,将整数放在引号中。
  • 如果它是一个布尔值,你为什么不使用:options={"default":false} ?

标签: php orm doctrine-orm


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

请注意,这使用 SQL DEFAULT,某些字段不支持,如 BLOBTEXT

【讨论】:

  • 好收获!官方文档中似乎没有 options={"default" = 0} 选项
  • 仅供参考,options 参数对于unsigned 值也很有用。看到这个answer
  • 我同时使用这个和公认的答案来涵盖所有基础。还请注意,您也可以这样做:options={"default": 0} 小心使用 " 而不是 ',因为它会导致我的教义版本出现错误。
  • 这应该是选择的答案!
  • 使用迁移时,这绝对是理想的解决方案,否则doctrine:migrations:diff 将无法理解您设置了默认值,因为它只扫描注释/元数据而不是 PHP 默认值.
【解决方案2】:

数据库默认值不受“可移植”支持。使用数据库默认值的唯一方法是通过columnDefinition 映射属性,您可以在其中为字段映射到的列指定SQL sn-p(包括DEFAULT 原因)。

你可以使用:

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

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

【讨论】:

  • 但是这里有个问题:如果我设置一个“datetime”类型呢?
  • @artragis 将您的实例化放在实体构造函数中
  • 必须小心使用这种方法进行迁移,因为任何现有的行都会导致迁移失败。
  • 不要使用实例化区域来设置变量...相信我,坏事会发生。请改用构造函数区域。
  • 我建议使用注解中的columnDefinition,否则有人会使用mysql客户端或phpmyadmin,值会出错...
【解决方案3】:

在您的实体中设置一个构造函数并在那里设置默认值。

【讨论】:

【解决方案4】:

用途:

options={"default":"foo bar"}

而不是:

options={"default"="foo bar"}

例如:

/**
* @ORM\Column(name="foo", type="smallint", options={"default":0})
*/
private $foo

【讨论】:

【解决方案5】:

更新

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

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

背景

以前的答案都没有帮助我解决我的具体情况,但我找到了解决方案。

我有一个表单域,它的行为如下:

  1. 不需要,可以留空。 (使用'必需' => false)
  2. 如果留空,则应默认为给定值。为了更好的用户体验,我没有在输入字段上设置默认值,而是使用了 html 属性“占位符”,因为它不那么突兀。

然后我尝试了这里给出的所有建议。让我列出它们:

  • 为实体属性设置默认值时:
<?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-&gt;isValid() 方法中的form-&gt;handleRequest() 将覆盖您的Entity 类上的这些默认值,并且将它们设置为输入字段值。如果输入字段值为空,则将Entity 属性设置为null

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

我的解决方法

form-&gt;isValid() 方法中的 form-&gt;handleRequest() 之后在控制器上设置默认值:

...
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-&gt;handleRequest() 方法不使用模型的setter 方法来更新数据(更多细节请深入form-&gt;setData())。

【讨论】:

  • 这个答案肯定会排在首位。表单组件使用 PropertyAccessor 获取和设置属性的值。也许属性访问器应该在方法可用时使用它们?
  • 布尔列不支持 php 的默认值,所以只有注释
  • 当信息来自表单时,这是唯一有效的解决方案。我也不同意上述关于布尔值的 cmets。他们不接受默认注释。
  • Symfony 表单组件使用模型设置器,但仅当表单的模型格式数据与模型对象实例的相应getter返回的数据不同时。如果您有自定义 setter/getter 方法 - 使用“property_path”表单选项(将由 PropertyAccessor 处理)或自定义 DataMapper(允许手动定义表单和模型对象之间的数据传输例程)。
  • 这个问题是关于教义,而不是 symfony,所以这个答案并不是真正的主题。
【解决方案6】:

我使用的解决方法是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');
}

【讨论】:

  • 对于未来的读者,不要依赖生命周期回调 :) 甚至 Marco Pivetta 也反对他们。
  • 警告!如果实体已经设置了 dtPosted 属性,那么您的代码将简单地覆盖该属性。如果存在访问器,请始终使用它们! if (!$this-&gt;getDtPosted()) { $this-&gt;setDtPosted(new \DateTime()); }
  • @emix 你能解释一下吗?
【解决方案7】:

您也可以使用 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\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 应用程序/控制台原则:模式:更新
    • 这是这里最糟糕的答案。 columnDefinition 直接违背了拥有 ORM 的目的,这是从数据库中抽象出来的。该解决方案将破坏可移植性,使您的软件依赖于您的数据库供应商,并且还将破坏 Doctrine Migrations 工具。
    • @PedroCordeiro 我完全同意你的看法。这只是一个快速的解决方案,直到出现另一个问题。
    【解决方案9】:

    也适用于我的 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"})
    【解决方案10】:

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

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

    private $default = 0;
    

    这插入了我想要的值。

    【讨论】:

    【解决方案11】:

    添加到@romanb 精彩的答案。

    这在迁移中增加了一点开销,因为您显然不能创建一个没有非空约束且没有默认值的字段。

    // 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");
    

    有了这个答案,我鼓励您思考为什么首先需要数据库中的默认值?通常是允许创建具有非空约束的对象。

    【讨论】:

      【解决方案12】:

      如果您对实体使用 yaml 定义, 以下适用于我的 postgresql 数据库:

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

      【讨论】:

      • 如果你在刷机前没有使用$entity-&gt;setFieldName()怎么办? Doctrine 似乎将默认值定义为 null。 yaml 中唯一的解决方案是定义默认值 IN 实体类,这对我来说似乎很愚蠢,因为它已经在 yaml 中定义了... -_-
      【解决方案13】:

      虽然在构造函数中设置值会起作用,但使用 Doctrine Lifecycle 事件可能是更好的解决方案。

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

      【讨论】:

      • 使用生命周期事件被视为hack。永远不要依赖黑客。
      【解决方案14】:

      我也遇到过同样的问题。我想将数据库中的默认值(自动)放入实体中。你猜怎么着,我做到了:)

      <?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";
      

      【讨论】:

      • 几年后回到这个问题,我建议你不要使用这种方法,这确实是一种 hacky hack。
      • 既然你不推荐你自己的答案,你还不如删掉它;)
      【解决方案15】:

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

      【讨论】:

        猜你喜欢
        • 2016-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-23
        • 2011-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多