Google Code 提供下列語言介面: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
將 JDO 資料物件儲存至資料存放區並不困難,只要呼叫 PersistenceManager 實例的 makePersistent() 方法即可。「應用服務引擎 JDO」實作會使用物件的主要金鑰欄位來追蹤資料物件所對應的資料存放區實體,還可以為新物件自動產生金鑰。您可以使用金鑰快速擷取實體,也可以使用已知的值 (例如帳戶 ID) 建構金鑰。
如要在資料存放區中儲存簡易資料物件,請呼叫 PersistenceManager 的 makePersistent() 方法,將物件傳送至實例。
PersistenceManager pm = PMF.get().getPersistenceManager();
Employee e = new Employee("Alfred", "Smith", new Date());
try {
pm.makePersistent(e);
} finally {
pm.close();
}
makePersistent() 呼叫是同步的,直到儲存物件且更新索引之後,呼叫才會傳回。
如要在 JDO 中儲存多個物件,請使用物件「集合」呼叫 makePersistentAll(...) 方法。在目前版本中,這個方法的實作類似一系列的 makePersistent() 呼叫。在未來版本中,這個方法將實行更具效率的資料存放區批次呼叫。
注意:如果資料物件的任何持續性欄位是其他持續性資料物件的參照,且該物件在載入後從未儲存或曾經變更,則這些參照物件也會儲存至資料存放區。請參閱「關聯性」。
在「應用服務引擎」中,每個實體都擁有唯一金鑰。完整金鑰包含多項資訊,包括應用程式 ID、種類和實體 ID。(金鑰也包含實體群組相關資訊;如需詳細資訊,請參閱「交易」)。
物件的金鑰會儲存在實例的欄位中。您可以使用 @PrimaryKey 註解來識別主要金鑰欄位。
建立物件之後,應用程式可以用字串形式提供金鑰的 ID 部分,或是讓資料存放區自動產生數字 ID。在資料存放區的所有實體中,完整金鑰必須是唯一的。換言之,物件的 ID 在所有相同種類和實體群組父系的物件 (如果有的話) 中,必須是獨一無二的。您可以使用欄位的類型和註解來選取想要的金鑰行為。
如果類別是關聯性中的「子系」類別,則金鑰欄位的類型必須能夠代表實體群組父系:Key 實例或是編碼成字串的 Key 值。如需取得實體群組的詳細資訊,請參閱「交易」;如需取得關聯性的詳細資訊,請參閱「關聯性」。
提示:如果應用程式建立新物件並給予字串 ID,但是該 ID 卻與另一個相同種類 (以及相同實體群組父系) 的物件 ID 完全相同,則儲存新物件將覆寫資料存放區中的另一個物件。建立新物件之前,如要偵測字串 ID 是否已遭使用,您可以使用交易來嘗試取得指定 ID 的實體;如果找不到實體,即可開始建立。請參閱「交易」。
主要金鑰欄位有四種類型:
長整數 (java.lang.Long),由資料存放區自動產生的實體 ID。如果物件沒有實體群組父系,且物件 ID 必須由資料存放區自動產生,請使用這種類型。儲存實例時,將填入實例的 Long 金鑰欄位。
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
// ...
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
字串 (java.lang.String),建立物件時由應用程式提供的實體 ID (「金鑰名稱」)。如果物件沒有實體群組父系,且物件 ID 必須由應用程式提供,請使用這種類型。應用程式會在儲存之前,將此欄位設為偏好的 ID。
import javax.jdo.annotations.PrimaryKey;
// ...
@PrimaryKey
private String name;
Key 實例 (com.google.appengine.api.datastore.Key)。金鑰值包括實體群組父系 (如果有的話) 的金鑰,以及應用程式指派的字串 ID 或系統產生的數字 ID。如要使用應用程式指派的字串 ID 來建立物件,您可以使用該 ID 建立 Key 值,再將欄位設為 Key 值。如要使用系統指派的數字 ID 來建立物件,您可以將金鑰欄位設為空值。(如需進一步瞭解如何使用實體群組父系,請參閱「交易」)。
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;
// ...
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
public void setKey(Key key) {
this.key = key;
}
應用程式可以使用 KeyFactory 類別建立 Key 實例:
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
// ...
Key key = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
Employee e = new Employee();
e.setKey(key);
pm.makePersistent(e);
與 Key 類型相似,但是其值採用金鑰的編碼字串形式。編碼字串金鑰可讓您攜帶編寫應用程式,同時享用「應用服務引擎」資料存放區實體群組的特點。
import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;
// ...
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String encodedKey;
應用程式可以在儲存之前,使用具備名稱的金鑰填入此值,或者保留空值。如果編碼金鑰欄位為空值,則儲存物件時,該欄位將填入系統產生的金鑰。
Key 實例可以透過 KeyFactory 的 keyToString() 方法轉換成編碼字串,而編碼字串可以透過 stringToKey() 方法轉換回 Key 實例。
使用編碼金鑰字串時,您可以透過額外欄位提供物件字串或數字 ID 的存取權限:
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String encodedKey;
@Extension(vendorName="datanucleus", key="gae.pk-name", value="true")
private String keyName;
// OR:
@Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
private Long keyId;
儲存物件之前,您可以將 "gae.pk-name" 欄位設為金鑰名稱。儲存物件之後,編碼金鑰欄位將填入包括金鑰名稱的完整金鑰。其類型必須是 String。
儲存物件之後,"gae.pk-id" 欄位將填入資料而且無法修改。其類型必須是 Long。
建立一個具備產生金鑰 (使用 valueStrategy = IdGeneratorStrategy.IDENTITY 的金鑰欄位) 的新物件之後,物件的金鑰值一開始為 null。隨著物件寫入資料存放區,金鑰欄位也會填入資料。如果您使用的是交易,則物件將於交易獲得認可時寫入。否則,必須等到呼叫 makePersistent() 方法建立物件時,或是呼叫 PersistenceManager 實例的 close() 方法更新物件時,才會寫入物件。
如果應用程式知道實體完整金鑰的每個元素,則應用程式不需要物件,即可建立相應的 Key 物件。
如果金鑰的實體沒有實體群組父系,則您可以使用 KeyFactory 類別的 createKey() 靜態方法。這個方法會採用一個種類 (類別的簡稱) 以及應用程式指派的字串 ID 或系統指派的數字 ID,然後傳回 Key 物件。舉例來說,假設實體的種類為 "Employee",金鑰名稱為 "Alfred.Smith@example.com",且沒有實體群組父系,如要為其重新建立金鑰:
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
// ...
Key k = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
假設實體的種類為 "Employee",系統指派的數字 ID 為 52234,且沒有實體群組父系,如要為其重新建立金鑰:
Key k = KeyFactory.createKey(Employee.class.getSimpleName(), 52234);
金鑰可以透過 KeyFactory 類別的 keyToString() 方法轉換成字串,而字串可以透過 stringToKey() 方法轉換成金鑰。(請注意,這與 Key 類別的 toString() 方法不同,後者會傳回適合偵錯、人類可讀的值)。
如果金鑰的實體擁有實體群組父系,則您可以使用 KeyFactory.Builder 類別:
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
// ...
Key k = new KeyFactory.Builder(Employee.class.getSimpleName(), 52234).addChild(ExpenseReport.class.getSimpleName(), "A23Z79").getKey();
Builder 實例的 addChild() 方法會傳回 Builder,因此您可以鏈結呼叫,以新增金鑰路徑的每個元素。如要取得指定產生器的完整 Key 值,您可以呼叫 Builder 的 getKey() 方法。
如需實體群組的詳細資訊,請參閱「交易」。
如要使用指定金鑰擷取物件,請使用 PersistenceManager 的 getObjectById() 方法。這個方法會使用物件的類別以及金鑰:
Key k = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
Employee e = pm.getObjectById(Employee.class, k);
如果類別所使用的金鑰欄位是未編碼的字串 ID (String) 或數字 ID (Long),則 getObjectByID() 可以使用簡單值做為金鑰參數:
Employee e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");
金鑰引數可以是任何一個支援的金鑰欄位類型 (字串 ID、數字 ID、Key 值、編碼金鑰字串),也可以是類別中與金鑰欄位不同的類型。「應用服務引擎」必須能夠從類別名稱與提供的值衍生出完整金鑰。字串 ID 和數字 ID 是互斥的,因此使用數字 ID 的呼叫絕對不會傳回字串 ID 的實體。如果使用 Key 值或編碼金鑰字串,則金鑰必須參考使用該類別代表其種類的實體。
透過 JDO 更新物件的方法之一就是擷取物件,然後在負責傳回物件的 PersistenceManager 仍然開啟時修改該物件。PersistenceManager 關閉之後,變更仍會持續。例如:
public void updateEmployeeTitle(User user, String newTitle) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Employee e = pm.getObjectById(Employee.class, user.getEmail());
if (titleChangeIsAuthorized(e, newTitle) {
e.setTitle(newTitle);
} else {
throw new UnauthorizedTitleChangeException(e, newTitle);
}
} finally {
pm.close();
}
}
由於 Employee 實例是由 PersistenceManager 所傳回,因此 PersistenceManager 知道 Employee 的 Persistent 欄位所做的所有變更,而且會在關閉時,自動為資料存放區更新這些修改。PersistenceManager 之所以知道這些,是因為 Employee 實例「已附加」至 PersistenceManager。
您可以宣告類別為「detachable」(可卸離的),即可在 PersistenceManager 關閉後修改物件。如要宣告,請將 detachable 屬性 (attribute) 新增至 @PersistenceCapable 註解:
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Employee {
// ...
}
現在,即使負責載入 Employee 物件的 PersistenceManager 關閉了,您仍然可以讀取與寫入該物件的欄位。下列範例將說明卸離物件的實用性:
public Employee getEmployee(User user) {
PersistenceManager pm = PMF.get().getPersistenceManager();
pm.setDetachAllOnCommit(true);
try {
e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");
} finally {
pm.close();
}
return e;
}
public void updateEmployeeTitle(Employee e, String newTitle) {
if (titleChangeIsAuthorized(e, newTitle) {
e.setTitle(newTitle);
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(e);
} finally {
pm.close();
}
} else {
throw new UnauthorizedTitleChangeException(e, newTitle);
}
}
如果使用卸離物件,即不需要建立資料傳輸物件。如需進一步瞭解如何運用卸離物件,請參閱 DataNucleus 文件。
如要從資料存放區刪除物件,請呼叫 PersistenceManager 的 deletePersistent() 方法並帶入該物件:
pm.deletePersistent(e);
如果物件欄位包含同屬持續性的子系物件,則子系物件也會一併遭到刪除。如需詳細資訊,請參閱「關聯性」。