2010-02-16 19 views
6

Tôi có một bảngBỏ qua các bản sao khi sử dụng INSERT trong một cơ sở dữ liệu với Symfony và Doctrine

CREATE TABLE `sob_tags_articles` (
    `tag_id` int(11) NOT NULL, 
    `article_id` int(11) NOT NULL, 
    `id` int(11) NOT NULL auto_increment, 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=112 

Và triing để lưu một đối tượng với Học thuyết:

$sbTagsArticles = new SobTagsArticles(); 
$sbTagsArticles->article_id = $pubId; 
$sbTagsArticles->tag_id = $tagId; 
$sbTagsArticles->save(); 

Nhưng nếu kỷ lục tồn tại với cùng $ Bản ghi mới pubId và $ tagId sẽ được chèn bằng PK mới.

Làm thế nào để thực hiện INSERT IGNORE trong bảng với symfony?

$sbTagsArticles->isNew(); 

lợi nhuận 1.

Thnx.

+0

Tại sao bạn không sử dụng '(tag_id, article_id)' làm khóa chính? –

+2

@ user274101: Bạn không cần thay đổi tiêu đề của câu hỏi đã giải quyết trên StackOverflow. Bạn nên chấp nhận câu trả lời đúng để thay thế. –

Trả lời

13
try 
{ 
    $record->save(); 
} 
catch(Doctrine_Exception $e) 
{ 
    if($e->getErrorCode() !== $duplicateKeyCode) 
    { 
     /** 
     * if its not the error code for a duplicate key 
     * value then rethrow the exception 
     */ 
     throw $e; 
    } 

    /** 
    * you might want to fetch the real record here instead 
    * so yure working with the persisted copy 
    */ 
} 

Bạn phải đảm bảo rằng cùng một bản ghi không tồn tại ở phía ứng dụng chứ không phải phía SQL. Nếu bạn không bao giờ muốn cùng một bài viết/thẻ kết hợp tồn tại thì hãy thêm một chỉ mục duy nhất vào (article_id, tag_id). Điều đó sẽ tạo ra một lỗi mysql mà sẽ lần lượt tạo ra một ngoại lệ giáo lý mà bạn có thể bắt. Không có cờ bỏ qua để lưu ... Bạn có thể sử dụng một thao tác ở mức thấp hơn của DBAL (Doctrine_Query, Doctrine_Connection, vv ..) nhưng không phải là directl từ lớp ORM.

Doctrine_Record::isNew() sẽ luôn trả về true nếu bạn có bản ghi được lập tức không thích hợp để kéo nó từ db nếu không có cách nào để biết rằng bản ghi là/không phải là mới.

Ngoài ra tại sao bạn sử dụng công cụ lưu trữ MyISAM? Im khá chắc chắn điều này sẽ thực sự dẫn đến chi phí cao hơn khi sử dụng Doctrine vì nó cần phải mô phỏng các ràng buộc ở phía php. Thông thường schema của bạn sẽ trông như thế này:

CREATE TABLE `sob_tags_articles` (
    `tag_id` int(11) NOT NULL, 
    `article_id` int(11) NOT NULL, 
    `id` int(11) NOT NULL auto_increment, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `some_unique_constraint_name_1` 
     FOREIGN KEY `article_id` 
     REFERENCES `article` (`id`) 
     ON DELETE CASCADE, 
    CONSTRAINT `some_unique_constraint_name_2` 
     FOREIGN KEY `tag_id` 
     REFERENCES `tag` (`id`) 
     ON DELETE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=112 
+0

oh cảm ơn! lược đồ đó sẽ tuyệt vời cho nhiệm vụ này, nhưng tôi không thể sửa đổi công cụ bảng. Và tôi đã đọc rằng Doctrine là tốt hơn và mới hơn mà Propel, vì vậy tôi sử dụng nó. Tôi đã thêm chỉ mục. Và bây giờ tôi cần bắt ngoại lệ Doctrine. Bạn có biết làm thế nào để làm điều đó? Tôi sử dụng một truy vấn ajax để lưu hồ sơ, vì vậy tôi không cần tất cả rác này được hiển thị trong firebug. – user274101

+0

Khối try/catch điển hình với một số logic để đảm bảo lỗi của nó mà bạn mong đợi ...bạn có thể cần phải kiểm tra mã lỗi i dont remebr nếu Doctrine ném một ngoại lệ chung Doctrine hoặc một cái gì đó cụ thể hơn. xem ví dụ trên. – prodigitalson

+0

ok, cảm ơn. Tôi nghĩ rằng vấn đề được giải quyết – user274101

-1

Bạn có thể kéo dài tuổi SobTagsArticles đối tượng với một phương pháp tiết kiệm mới, và kiểm tra xem các kỷ lục đã tồn tại:

public function exists() { 
    $q = Doctrine_Query::create() 
    ->from('sobtagsarticles ta') 
    ->where('ta.tag_id = ? and ta.article_id = ?', array($this->getTagId(), $this->getArticleId())); 

    if (!$result = $q->execute()) 
    { 
    parent::save(); 
    } 
} 

Bằng cách này, đối tượng sẽ được lưu chỉ khi nó không tồn tại.

Bạn cũng có thể thiết lập một chỉ số duy nhất để bàn của bạn như sau:

UNIQUE INDEX `sb_tags_articles_unique` (`tag_id` ASC, `article_id` ASC) 

schema của bạn sẽ trông như thế này:

CREATE TABLE `sob_tags_articles` (
    `tag_id` int(11) NOT NULL, 
    `article_id` int(11) NOT NULL, 
    `id` int(11) NOT NULL auto_increment, 
    PRIMARY KEY (`id`), 
    UNIQUE INDEX `sb_tags_articles_unique` (`tag_id` ASC, `article_id` ASC), 
    CONSTRAINT `some_unique_constraint_name_1` 
     FOREIGN KEY `article_id` 
     REFERENCES `article` (`id`) 
     ON DELETE CASCADE, 
    CONSTRAINT `some_unique_constraint_name_2` 
     FOREIGN KEY `tag_id` 
     REFERENCES `tag` (`id`) 
     ON DELETE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=112 
+0

Tôi nghĩ tốt hơn là không truy vấn mysql một lần nữa để kiểm tra xem bản ghi có tồn tại hay không. – user274101

+0

Có, bạn có thể sử dụng hàng đợi memcached hoặc redis thay vào đó –

6

này được mã thực tế để được sử dụng

try 
{ 
    $record->save(); 
} 
catch(Doctrine_Connection_Exception $e) 
{ 
    if($e->getPortableCode() != Doctrine::ERR_ALREADY_EXISTS) 
    { 
     /** 
     * if its not the error code for a duplicate key 
     * value then rethrow the exception 
     */ 
     throw $e; 
    } 
    /** 
    * you might want to fetch the real record here instead 
    * so yure working with the persisted copy 
    */ 
} 
Các vấn đề liên quan