2012-09-26 57 views
14

使用這些類,您將如何將「Person」的記錄更改爲「Employee」。Doctrine:SINGLE_TABLE的更新鑑別器繼承

/** 
* @Entity 
* @InheritanceType("SINGLE_TABLE") 
* @DiscriminatorColumn(name="discr", type="string") 
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) 
*/ 
class Person 
{ 
    // ... 
} 

/** 
* @Entity 
*/ 
class Employee extends Person 
{ 
    // ... 
} 

我試着改變鑑別器列的值,但我無法訪問它。我也嘗試創建一個'員工'實例並手動複製數據,但不適用於自動遞增身份證。它只是作爲新記錄添加,而不是更新現有記錄。

我是否需要編寫一個自定義的sql查詢,或者我正在做其他根本錯誤的其他操作?

回答

32

當一個對象實例的類型需要隨時間變化時,這不是一個好兆頭。我不是在談論這裏的向下轉換/向上轉換,而是在需要改變對象的實際類型。

首先,讓我來告訴你爲什麼這是一個壞主意:

  1. 子類可以定義多個屬性,並在它的構造函數中做一些其它附加的工作 。我們應該再次運行新的構造函數嗎? 如果它覆蓋了我們的一些舊對象的屬性?
  2. 如果你在代碼的某個部分工作了一個Person的實例,然後它突然變換成一個Employee(它可能有一些你不會期望的重新定義的行爲)?

這就是爲什麼大多數語言不會允許您在執行期間(和內存,當然,但我不想詳述)更改對象的真實類類型的原因的一部分。有些可以讓你這樣做(有時以扭曲的方式,例如JVM),但這實際上並不是很好的做法!

更多的時候,需要這樣做的地方在於面向對象的設計決策。

由於這些原因,Doctrine不允許您更改實體對象的類型。當然,你可以寫簡單的SQL(在這篇文章的結尾 - 但請通讀!)反正做的修改,但這裏的兩個「乾淨」的選項,我建議:

我意識到你已經說第一個選項不是一個選項,但我花了一段時間寫下這篇文章,所以我覺得我應該儘可能完整地爲將來參考。

  1. 每當你需要從Person「式的改變」,以Employee,創建Employee的一個新實例,並複製你想從舊Person對象複製到Employee對象中的數據。不要忘記刪除舊的實體並堅持新的實體。
  2. 使用組合而不是繼承(有關詳細信息和其他文章的鏈接,請參閱此wiki article)。 編輯:對於它的地獄,here's a part of a nice conversation with Erich Gamma關於「構成的繼承」!

查看相關討論herehere


現在,這裏是平原SQL方法我早先提到 - 我希望你不會需要使用它!

確保您的查詢已過濾(因爲查詢將在未經任何驗證的情況下執行)。

$query = "UPDATE TABLE_NAME_HERE SET discr = 'employee' WHERE id = ".$entity->getId(); 
$entity_manager->getConnection()->exec($query); 

下面是這是在DBAL\Connection類(供參考)exec方法的文檔和代碼:

/** 
* Execute an SQL statement and return the number of affected rows. 
* 
* @param string $statement 
* @return integer The number of affected rows. 
*/ 
public function exec($statement) 
{ 
    $this->connect(); 
    return $this->_conn->exec($statement); 
} 
+1

非常感謝你。高枕無憂;我會採取你的建議,避免普通的SQL。 – Nate

+0

偶然發現了兩次,它確實幫了我。謝謝! – Strategist