2010-11-13 54 views
1

我有一個類可以保存到appengine數據存儲中,其中包含一個Text字段(類似字符串的appengine數據類型,但不限於500個字符)。也是一個基本相同的雙胞胎類,但在客戶端使用(即沒有任何com.google.appengine.api.datastore。*導入)。如何從客戶端的appengine數據存儲元素中獲取文本字段

是否有任何數據類型,它可以讓我將Text服務器端字段保存到客戶端?

一個可能的選擇將要拆分的文成一些字符串,但聽起來很醜陋......

有什麼建議?

回答

0

一些補充,以自定義的序列化圖書館之前發佈

http://juristr.com/blog/2010/02/gwt-app-engine-and-app-engine-data/ http://www.resmarksystems.com/code/ - 獲得com.google.appengine.api.datastore.Text並轉移到其他客戶端數據存儲類型)

還需要更新com.google.appengine.eclipse.core.prefs包含庫: filesCopiedToWebInfLib = ... | appengine-utils-client-1.1.jar

另一個解決方法是使字符串可序列化blob克服1500字節的限制(它會丟失排序和過濾能力冷杉此字段):​​

@Persistent(serialized = "true") 
public String content; 

所以能夠對客戶端較少的開銷從com.google.appengine.api.datastore.Text轉換爲字符串與生命週期聽衆(不是實例監聽者,他們會發送給客戶端並使其失敗)。將其與自定義序列化一起使用,允許客戶端支持com.google.appengine.api.datastore.Text而無需額外的傳輸類。

com.google.appengine.api.datastore.Text可能在發送給客戶端之前清除,以避免發送開銷(最簡單的方法是將其標記爲瞬態)。

在服務器端,我們必須避免直接設置String屬性,因爲jdo不會捕捉它的更改(只會捕獲新記錄或在某些持久字段被修改後)。這是非常小的開銷。

記錄的分離應通過pm.makeTransient進行。當使用pm.detachCopy時,需要將實體標記爲detachable =「true」(將調用DetachLifecycleListener)並實現DetachLifecycleListener.postDetach,與StoreLifecycleListener.preStore類似。不會複製非持久性字段(由pm.detachCopy複製),並且在客戶端將爲空。

有可能處理幾類類似的方式

import javax.jdo.JDOHelper; 
import javax.jdo.PersistenceManager; 
import javax.jdo.PersistenceManagerFactory; 
import javax.jdo.listener.DetachLifecycleListener; 
import javax.jdo.listener.InstanceLifecycleEvent; 
import javax.jdo.listener.LoadLifecycleListener; 
import javax.jdo.listener.StoreLifecycleListener; 

import com.google.appengine.api.datastore.Text; 
import com.mycompany.mywebapp.shared.Entity; 
import com.mycompany.mywebapp.shared.Message; 

@SuppressWarnings("rawtypes") 
public class PersistenceManagerStuff 
{ 
    public static final PersistenceManagerFactory PMF = JDOHelper.getPersistenceManagerFactory("transactions-optional"); 

    public static EntityLifecycleListener entityLifecycleListener = new EntityLifecycleListener(); 
    public static Class[] entityClassList = new Class[] { Entity.class }; 

    public static MessageLifecycleListener messageLifecycleListener = new MessageLifecycleListener(); 
    public static Class[] messageClassList = new Class[] { Message.class }; 

    public static PersistenceManager getPersistenceManager() 
    { 
     PersistenceManager pm = PMF.getPersistenceManager(); 
     pm.addInstanceLifecycleListener(entityLifecycleListener, entityClassList); 
     pm.addInstanceLifecycleListener(messageLifecycleListener, messageClassList); 
     return pm; 
    } 

    // [start] lifecycle listeners 

    public static class EntityLifecycleListener implements LoadLifecycleListener, StoreLifecycleListener//, DetachLifecycleListener 
    { 
     public void postLoad(InstanceLifecycleEvent event) 
     { 
      Entity entity = ((Entity) event.getSource()); 
      if (entity.content_long != null) 
       entity.content = entity.content_long.getValue(); 
      else 
       entity.content = null; 
     } 

     public void preStore(InstanceLifecycleEvent event) 
     { 
      Entity entity = ((Entity) event.getSource()); 
      entity.setContent(entity.content); 
      /* 
      need mark class @PersistenceAware to use code below, otherwise use setter 
      if (entity.content != null) 
       entity.content_long = new Text(entity.content); 
      else 
       entity.content_long = null; 
      */ 
     } 

     public void postStore(InstanceLifecycleEvent event) 
     { 
     } 

     /*public void postDetach(InstanceLifecycleEvent event) 
     { 
     } 

     public void preDetach(InstanceLifecycleEvent event) 
     { 
     }*/ 
    } 

    public static class MessageLifecycleListener implements LoadLifecycleListener, StoreLifecycleListener 
    { 
     public void postLoad(InstanceLifecycleEvent event) 
     { 
      Message message = ((Message) event.getSource()); 
      if (message.content_long != null) 
       message.content = message.content_long.getValue(); 
      else 
       message.content = null; 
     } 

     public void preStore(InstanceLifecycleEvent event) 
     { 
      Message message = ((Message) event.getSource()); 
      message.setContent(message.content); 
     } 

     public void postStore(InstanceLifecycleEvent event) 
     { 
     } 
    } 

    // [end] lifecycle listeners 
} 

@SuppressWarnings("serial") 
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "false") 
public class Entity implements Serializable 
{ 
    @PrimaryKey 
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
    public Long id; 

    @NotPersistent 
    public String content; 

    @Persistent(column = "content") 
    public transient com.google.appengine.api.datastore.Text content_long; 

    public void setContent(String content) 
    { 
     this.content = content; 
     if (content != null) 
      content_long = new Text(content); 
     else 
      content_long = null; 
    } 

    public Entity() {} 
} 

@PersistenceAware 
public class DataServiceImpl extends RemoteServiceServlet implements DataService 
{ 
    public Entity renameEntity(long id, String newContent) throws NotLoggedInException 
    { 
     PersistenceManager pm = PersistenceManagerStuff.getPersistenceManager(); 
     Entity result = null; 

     try 
     { 
      Entity entity = (Entity) pm.getObjectById(Entity.class, id); 
      if (entity.longUserId != getLongUserId(pm)) 
       throw new NotLoggedInException(String.format("wrong entity %d ownership", entity.id)); 

      entity.modificationDate = java.lang.System.currentTimeMillis(); // will call lifecycle handlers for entity.content, but is still old value 
      //entity.content = newContent; // will not work, even owner class is @PersistenceAware 
      entity.setContent(newContent); // correct way to set long value 

      pm.makeTransient(result = entity); 
     } 
     catch (Exception e) 
     { 
      LOG.log(Level.WARNING, e.getMessage()); 
      throw e; 
     } 
     finally 
     { 
      pm.close(); 
     } 

     return result; 
    } 
} 

也是在生命週期處理程序,可以將舊(短)和新的(長),如果你有兩個(不同的字段值成單一的實體名稱),並不想將舊的轉換爲新的。但似乎com.google.appengine.api.datastore。文本支持從舊字符串值加載。

一些低級別的代碼批量轉換舊值到新的(使用低級別的列舉API):

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 
Query q = new Query("Entity"); 
PreparedQuery pq = datastore.prepare(q); 

for (com.google.appengine.api.datastore.Entity result : pq.asIterable()) 
{ 
    String content = (String) result.getProperty("content"); 
    if (content != null) 
    { 
     result.setProperty("content", new com.google.appengine.api.datastore.Text(content)); 
     datastore.put(result); 
    } 
} 
相關問題