Giá trị mặc định trong Học thuyết


338

Làm cách nào để đặt giá trị mặc định trong Học thuyết 2?


26
@ORM \ Cột (name = "foo", type = "binary", precision = 7, scale = 2, Options = {"default" = 0}) hoạt động (từ câu trả lời không phổ biến bên dưới)
WayFarer

2
@ORM \ Cột (name = "is_activated", type = "boolean", tùy chọn = {"mặc định": 0}) HOẶC @ORM \ Cột (name = "is_activated", type = "boolean", tùy chọn = {"mặc định "= 0})
ahmed hamdy

Ahmed này dường như không hoạt động cho booleans trong Symfony 2.3. Tuy nhiên, các tùy chọn = {"default" = "0"}) không hoạt động, đặt số nguyên trong dấu ngoặc kép.
Acyra

4
Nếu đó là boolean, tại sao bạn không sử dụng: tùy chọn = {"mặc định": false}?
robocoder

Câu trả lời:


385

Các giá trị mặc định của cơ sở dữ liệu không được "hỗ trợ" một cách hợp lý. Cách duy nhất để sử dụng các giá trị mặc định của cơ sở dữ liệu là thông qua columnDefinitionthuộc tính ánh xạ nơi bạn chỉ định SQLđoạn mã ( DEFAULTbao gồm nguyên nhân) cho cột mà trường được ánh xạ tới.

Bạn có thể dùng:

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

Các giá trị mặc định ở cấp độ PHP được ưa thích vì chúng cũng có sẵn trên các đối tượng mới được tạo và tồn tại (Doctrine sẽ không quay lại cơ sở dữ liệu sau khi duy trì một đối tượng mới để lấy các giá trị mặc định).


11
nhưng có một vấn đề ở đây: Nếu tôi đặt loại "datetime" thì sao?
artragis

46
@artragis đặt instancration của bạn vào hàm tạo thực thể
Alain Tiemblo

16
Phải cẩn thận với việc di chuyển bằng cách sử dụng phương pháp này vì bất kỳ hàng nào hiện có sẽ khiến việc di chuyển thất bại.
Tamlyn

7
Không sử dụng khu vực khởi tạo để đặt biến ... Hãy tin tôi, điều tồi tệ sẽ xảy ra. Sử dụng khu vực xây dựng thay thế.
mimoralea

4
Tôi khuyên bạn nên sử dụng cột Định nghĩa trong chú thích hoặc ai đó sẽ sử dụng máy khách mysql hoặc phpmyadmin và các giá trị sẽ sai ...
NDM

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

Lưu ý rằng điều này sử dụng SQL DEFAULT, không được hỗ trợ cho một số trường như BLOBTEXT.


4
Nắm bắt tốt! Có vẻ như không có tùy chọn = {"default" = 0} trong tài liệu chính thức
WayFarer

2
FYI, optionstham số cũng hữu ích cho unsignedcác giá trị. xem câu trả lời
yvoyer

5
Tôi sử dụng cả điều này và câu trả lời được chấp nhận để bao gồm tất cả các cơ sở. Cũng chỉ là một lưu ý mà bạn cũng có thể làm: options={"default": 0}Cẩn thận sử dụng "chứ không phải", vì nó gây ra lỗi trong phiên bản giáo lý của tôi.
Scott Flack

28
Đây phải là câu trả lời được lựa chọn!
Acelasi Eu

2
@Matt có lẽ ông đã nói rằng vì đó là một tính năng không có giấy tờ, và các tính năng không có giấy tờ dễ bị xóa. Như đã được ghi lại, bạn nên an toàn khi sử dụng nó.
JCM

62

Thiết lập một hàm tạo trong thực thể của bạn và đặt giá trị mặc định ở đó.


Điều này chắc chắn có vẻ như cách tiếp cận hợp lý. Có ai gặp vấn đề với việc thiết lập mặc định trong hàm tạo không?
cantera

26
Giải pháp được đề xuất của doctrine
cantera

@ cantera25 nên là câu trả lời +1
Phill Pafford

3
điều này không cập nhật các thực thể hiện có nếu bạn thêm trường mới cần có giá trị mặc định. Vì vậy, không nên là câu trả lời. phụ thuộc vào chính xác những gì bạn cần làm
Tomáš Tibenský

Nó sẽ không hoạt động trên mục đích cập nhật. Nếu bạn muốn quay trở lại giá trị mặc định bằng cách làm trống trường (ngay cả đối với số nguyên), thật không may, nó sẽ không hoạt động.
ThEBiShOp


51

Cập nhật

Thêm một lý do tại sao đọc tài liệu cho Symfony sẽ không bao giờ lỗi thời. Có một giải pháp đơn giản cho trường hợp cụ thể của tôi và là đặt field typetùy chọn empty_datathành giá trị mặc định.

Một lần nữa, giải pháp này chỉ dành cho kịch bản trong đó một đầu vào trống trong biểu mẫu đặt trường DB thành null.

Lý lịch

Không có câu trả lời nào trước đây giúp tôi với kịch bản cụ thể của mình nhưng tôi đã tìm ra giải pháp.

Tôi đã có một trường mẫu cần hành xử như sau:

  1. Không yêu cầu, có thể để trống. (Được sử dụng 'bắt buộc' => sai)
  2. Nếu để trống, nó sẽ mặc định thành một giá trị nhất định. Để có trải nghiệm người dùng tốt hơn, tôi đã không đặt giá trị mặc định trên trường đầu vào mà chỉ sử dụng thuộc tính html 'giữ chỗ' vì nó ít gây khó chịu.

Sau đó tôi đã thử tất cả các khuyến nghị được đưa ra ở đây. Hãy để tôi liệt kê chúng:

  • Đặt giá trị mặc định khi cho thuộc tính thực thể:
<?php
/**
 * @Entity
 */
class myEntity {
    /**
     * @var string
     *
     * @Column(name="myColumn", type="string", length="50")
     */
    private $myColumn = 'myDefaultValue';
    ...
}
  • Sử dụng chú thích tùy chọn:
@ORM\Column(name="foo", options={"default":"foo bar"})
  • Đặt giá trị mặc định trên hàm tạo:
/**
 * @Entity
 */
class myEntity {
    ...
    public function __construct()
    {
        $this->myColumn = 'myDefaultValue';
    }
    ...
}
Không ai trong số đó hoạt động và tất cả vì cách Symfony sử dụng lớp Thực thể của bạn.

QUAN TRỌNG

Các trường biểu mẫu Symfony ghi đè các giá trị mặc định được đặt trên lớp Thực thể. Có nghĩa là, lược đồ cho DB của bạn có thể có một giá trị mặc định được xác định nhưng nếu bạn để trống một trường không bắt buộc khi gửi biểu mẫu của bạn, form->handleRequest()bên trong form->isValid()phương thức của bạn sẽ ghi đè các giá trị mặc định đó trên Entitylớp của bạn và đặt chúng thành các giá trị trường đầu vào. Nếu các giá trị trường đầu vào trống, thì nó sẽ đặt thuộc Entitytính thành null.

http://symfony.com/doc/cản/book/forms.html#handling-form-submissions

Cách giải quyết của tôi

Đặt giá trị mặc định trên bộ điều khiển của bạn sau form->handleRequest()bên trong form->isValid()phương thức của bạn :

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

Không phải là một giải pháp đẹp nhưng nó hoạt động. Tôi có thể có thể thực hiện validation groupnhưng có thể có người coi vấn đề này là chuyển đổi dữ liệu thay vì xác thực dữ liệu , tôi để bạn quyết định.


Ghi đè Setter (Không hoạt động)

Tôi cũng đã cố gắng ghi đè Entitysetter theo cách này:

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

    return $this;
}
...

Điều này, mặc dù nó trông sạch hơn, nhưng nó không hoạt động . Lý do là form->handleRequest()phương thức tà ác không sử dụng các phương thức setter của Model để cập nhật dữ liệu (tìm form->setData()hiểu thêm chi tiết).


Câu trả lời này nên đi đến đầu cho chắc chắn. Thành phần biểu mẫu sử dụng PropertyAccessor để nhận và đặt các giá trị cho các thuộc tính của bạn. Có lẽ người truy cập tài sản nên sử dụng các phương pháp khi chúng có sẵn?
Xobb

1
các cột boolean không hỗ trợ mặc định từ php, vì vậy chỉ chú thích
Crusader

Đây là giải pháp duy nhất hoạt động khi thông tin đến từ các biểu mẫu. Ngoài ra tôi không đồng ý với ý kiến ​​trên liên quan đến boolean. Họ không chấp nhận chú thích mặc định.
BernardA

Thành phần biểu mẫu Symfony sử dụng setters mô hình nhưng chỉ khi dữ liệu định dạng mô hình của biểu mẫu khác với dữ liệu được trả về bởi getter tương ứng của thể hiện đối tượng mô hình. Nếu bạn có các phương thức setter / getter tùy chỉnh của mình - hãy sử dụng tùy chọn biểu mẫu "property_path" (sẽ được xử lý bởi PropertyAccessor) hoặc DataMapper tùy chỉnh (cho phép xác định thủ công thói quen truyền dữ liệu giữa biểu mẫu và đối tượng mô hình).
Arkemlar

1
Câu hỏi này là về học thuyết, không phải sự tương giao, vì vậy câu trả lời này không thực sự thuộc chủ đề.
Omn

18

Cách giải quyết tôi sử dụng là a LifeCycleCallback. Vẫn đang chờ xem liệu có phương pháp "gốc" nào nữa không @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
Đối với độc giả trong tương lai, đừng dựa vào các cuộc gọi lại vòng đời :) ngay cả Marco Pivetta cũng chống lại họ.
emix

Cảnh báo! Nếu Thực thể đã đặt thuộc tính dtPosted, thì mã của bạn sẽ chỉ ghi đè lên thuộc tính. Luôn luôn sử dụng phụ kiện nếu chúng tồn tại! if (!$this->getDtPosted()) { $this->setDtPosted(new \DateTime()); }
Barh

13

Bạn cũng có thể làm điều đó bằng 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

Đây là cách tôi giải quyết nó cho chính mình. Dưới đây là một ví dụ thực thể với giá trị mặc định cho MySQL. Tuy nhiên, điều này cũng yêu cầu thiết lập một hàm tạo trong thực thể của bạn và để bạn đặt giá trị mặc định ở đó.

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'

Với dòng này trong cấu hình của tôi, Doctrine cố gắng bỏ mặc định trên cột mỗi lần tôi chạy. Học thuyết ứng dụng / bảng điều khiển php: lược đồ: cập nhật
shapeshifter

1
Đây là câu trả lời tồi tệ nhất ở đây. columnDefinitiontrực tiếp thực hiện lại mục đích có ORM, đó là sự trừu tượng hóa từ cơ sở dữ liệu. Giải pháp này sẽ phá vỡ tính di động, sẽ giữ cho phần mềm của bạn phụ thuộc vào nhà cung cấp DB của bạn và cũng sẽ phá vỡ các công cụ Di chuyển học thuyết.
Pedro Cordeiro

@PedroCordeiro Tôi hoàn toàn đồng ý với bạn. Đây chỉ là một giải pháp nhanh chóng cho đến khi một vấn đề khác tăng lên.
Putna

7

Cũng hoạt động với tôi trên cơ sở dữ liệu mysql:

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

Trong định dạng chú thích cho ai quan tâm: @ORM \ Cột (name = "Entity_name", gõ = "số nguyên", tùy chọn = {"mặc định" = "1"})
Hannes

7

Không ai trong số này làm việc cho tôi. Tôi tìm thấy một số tài liệu trên trang web của học thuyết nói rằng đặt giá trị trực tiếp để đặt giá trị mặc định.

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;

Điều này chèn giá trị tôi muốn.


Vui lòng thay đổi liên kết đến doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/ trộm Xem điểm 3.2.2. Làm cách nào để thêm giá trị mặc định vào cột?
Tobi


3

Thêm vào câu trả lời tuyệt vời @romanb.

Điều này thêm một chút chi phí trong quá trình di chuyển, vì rõ ràng bạn không thể tạo một trường không có ràng buộc null và không có giá trị mặc định.

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

Với câu trả lời này, tôi khuyến khích bạn nghĩ tại sao bạn cần giá trị mặc định trong cơ sở dữ liệu ngay từ đầu? Và thông thường, nó là cho phép tạo các đối tượng không ràng buộc null.


3

Nếu bạn sử dụng định nghĩa yaml cho thực thể của mình, thì công việc sau đây đối với tôi trên cơ sở dữ liệu postgresql:

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

1
Điều gì nếu bạn không sử dụng $entity->setFieldName()trước khi xả? Học thuyết dường như xác định giá trị mặc định ở mức null. Giải pháp duy nhất trong yaml là xác định giá trị mặc định IN lớp thực thể có vẻ ngu ngốc đối với tôi vì nó đã được định nghĩa trong yaml ... -_-
j0k

1

Tôi vật lộn với cùng một vấn đề. Tôi muốn có giá trị mặc định từ cơ sở dữ liệu vào các thực thể (tự động). Đoán xem, tôi đã làm nó :)

<?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
Trở lại vấn đề này từ hơn một vài năm, tôi khuyên bạn không nên sử dụng phương pháp này, nó thực sự là một bản hack.
Steffen Brem

Vì bạn không đề xuất câu trả lời của riêng mình, bạn cũng có thể xóa nó đi;)
Dragos

1

Trong khi đặt giá trị trong hàm tạo sẽ hoạt động, sử dụng các sự kiện Vòng đời của Doctrine có thể là một giải pháp tốt hơn.

Bằng cách tận dụng prePersistSự kiện Vòng đời, bạn có thể chỉ đặt giá trị mặc định cho thực thể của mình trong lần duy trì ban đầu.


Sử dụng các sự kiện vòng đời được coi là a hack. Không bao giờ dựa vào hack.
emix

0

Hãy cẩn thận khi đặt giá trị mặc định trên định nghĩa thuộc tính! Làm điều đó trong constructor thay vào đó, để giữ cho nó không có vấn đề. Nếu bạn định nghĩa nó trên định nghĩa thuộc tính, sau đó duy trì đối tượng vào cơ sở dữ liệu, sau đó thực hiện tải một phần, sau đó các thuộc tính không được tải sẽ lại có giá trị mặc định. Điều đó là nguy hiểm nếu bạn muốn tiếp tục đối tượng một lần nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.