2016-03-16 16 views
5

tôi có các nguyên tắc sau trong BlockedTable.php tôiCakePHP 3 Nhiều isUnique cho phép NULL trùng lặp

public function buildRules(RulesChecker $rules) 
{ 
    $rules->add($rules->isUnique(['date', 'time']), 
     ['message' => 'unique error']); 

    return $rules; 
} 

Cho đến bây giờ điều này đã làm việc tốt - nếu tôi cố gắng tiết kiệm một kỷ lục mới với ngày và thời gian đã tồn tại , nó ngăn cản tôi tiết kiệm.

Tuy nhiên, nếu thời gian của tôi là NULL, chẳng hạn như mục nhập bên dưới;

╔════╦══════════════╦═══════╗ 
║ ID ║ Date  ║ Time ║ 
╠════╬══════════════╬═══════╣ 
║ 1 ║ 22/08/1985 ║ NULL ║ 
╚════╩══════════════╩═══════╝ 

Quy tắc vẫn cho phép tôi lưu mục nhập mới có cùng dữ liệu. Vì vậy, nếu tôi cố gắng tiết kiệm $date = 22/08/1985$time = NULL nó tiết kiệm tốt và có một bản ghi trùng lặp trong cơ sở dữ liệu của tôi. Tôi mong đợi nó đã thất bại do quy tắc trên?

Tại sao điều này lại xảy ra? Và làm cách nào tôi có thể ngăn các mục nhập trùng lặp trên các giá trị NULL?

Cảm ơn trước sự giúp đỡ của bạn.

Trả lời

2

So sánh với NULL sử dụng toán tử so sánh bình thường, tức là column = NULL (mà sự cai trị độc đáo không), nên luôn luôn NULL (AFAIK này ít nhất là trường hợp trong MySQL và Postgres), do đó không có gì đã được tìm thấy, và do đó độc đáo kiểm tra sẽ vượt qua bất cứ khi nào có một giá trị NULL tham gia.

Nếu bạn muốn ngăn chặn hành vi này, bạn sẽ phải sử dụng quy tắc tùy chỉnh, vì quy tắc được tích hợp sẵn không hỗ trợ nó. Tôi nghĩ đây là thứ đáng để nâng cao, vì vậy bạn có thể muốn mở một vé over at GitHub. Dưới đây là một ví dụ cơ bản cho lớp quy tắc IsUnique được ghi đè, về cơ bản, chỉ cần thêm một toán tử IS vào khóa điều kiện, để kiểm tra NULL kết thúc là column IS NULL.

public function __invoke(EntityInterface $entity, array $options) 
{ 
    if (!$entity->extract($this->_fields, true)) { 
     return true; 
    } 

    $alias = $options['repository']->alias(); 
    $conditions = $this->_alias($alias, $entity->extract($this->_fields)); 
    if ($entity->isNew() === false) { 
     $keys = (array)$options['repository']->primaryKey(); 
     $keys = $this->_alias($alias, $entity->extract($keys)); 
     if (array_filter($keys, 'strlen')) { 
      $conditions['NOT'] = $keys; 
     } 
    } 

    // handle null values 
    foreach ($conditions as $key => $value) { 
     if ($value === null) { 
      $conditions[$key . ' IS'] = $value; 
      unset($conditions[$key]); 
     } 
    } 

    return !$options['repository']->exists($conditions); 
} 

Về mặt lý thuyết, bạn có thể làm điều đó trong một IsUnique::_alias() phương pháp overriden quá, mà sẽ làm việc mà không cần phải reimplement mã từ lớp cai trị ban đầu, nó không thực sự đúng nơi mặc dù.

https://github.com/cakephp/cakephp/blob/3.2.5/src/ORM/Rule/IsUnique.php

Xem thêm

+0

Cảm ơn cho câu trả lời ndm sâu, tôi sẽ cân nhắc lựa chọn của tôi và trong khi chờ đợi tạo ra một vé tăng cường . – JayIsTooCommon

+0

Và đã làm quy tắc tùy chỉnh và hoạt động hoàn hảo. Cảm ơn một lần nữa – JayIsTooCommon

Các vấn đề liên quan