2011-12-04 31 views
0

使用db4o客戶端/服務器,更新不適用於對象的集合屬性。我使用透明持久性,但這沒有幫助。然後,我將Collection屬性更改爲ActivatableCollection,但沒有運氣。db4o透明持久不工作

這是服務器設置:

private void StartDatabase() 
{ 
    IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration(); 

    serverConfiguration.Networking.MessageRecipient = this; 

    serverConfiguration.Common.Add(new TransparentActivationSupport()); 
    serverConfiguration.Common.Add(new TransparentPersistenceSupport()); 

    string db4oDatabasePath  = AppDomain.CurrentDomain.BaseDirectory; 
    string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];    
    int databaseServerPort  = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture); 

    _db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort); 

    string databaseUser  = ConfigurationManager.AppSettings["databaseUser"]; 
    string databasePassword = ConfigurationManager.AppSettings["databasePassword"]; 

    _db4oServer.GrantAccess(databaseUser, databasePassword); 
} 

這是我要救實體:

​​

這是應用程序的實體中的屬性:

public ActivatableCollection<TaskBase> Tasks { get; private set; } 

這是更新集合中每個對象的客戶端代碼:

Application application = (from Application app in db 
             where app.Name == "Foo" 
             select app).FirstOrDefault(); 

      foreach (TaskBase task in application.Tasks) 
      { 
       task.Description += "."; 
      } 

      db.Store(application); 

奇怪的是,db.Commit()也沒有工作。

有兩種解決方法,但我寧願這樣做的「正確」的方式。

解決方法1:在更改每個任務時調用db.Store(任務)。

變通辦法2:調用db.Store(),在此之前:

db.Ext().Configure().UpdateDepth(5); 

誰能告訴我,爲什麼名單沒有更新?

如果有幫助,這裏是ActivatableCollection類:

public class ActivatableCollection<T> : Collection<T>, IActivatable 

{ 
    [Transient] 
    private IActivator _activator; 

/// <summary> 
/// Activates the specified purpose. 
/// </summary> 
/// <param name="purpose">The purpose.</param> 
public void Activate(ActivationPurpose purpose) 
{ 
    if (this._activator != null) 
    { 
     this._activator.Activate(purpose); 
    } 
} 

/// <summary> 
/// Binds the specified activator. 
/// </summary> 
/// <param name="activator">The activator.</param> 
public void Bind(IActivator activator) 
{ 
    if (_activator == activator) { return; } 

    if (activator != null && null != _activator) { throw new System.InvalidOperationException(); } 

    _activator = activator; 
} 

}

+0

通過大量的試驗和錯誤,以及RTFM,我進展緩慢。我發現我沒有使用透明持久性。看來服務器和客戶端配置需要TransparentPersistenceSupport配置。而且我錯過了我必須致電每個實體的每個獲取器和設置器的地方。不是很透明... –

+0

這樣做意味着我必須爲每個屬性實現手動獲取和設置器。域實體應該對持久層一無所知,但這種方法在每個實體上都有db4o代碼。明確保存每個對象可能會更容易。我會這樣做,如果我能弄清楚爲什麼添加一個新的對象到現有的列表不會持久對象和父對象之間的關聯。例如:Foo有屬性列表。當我做Bars.Add(新酒吧())時,新酒吧被存儲,但它不與Foo關聯。 –

回答

0

我是能夠得到透明激活和持久性的工作。由於我上面評論中提到的原因,我決定不採用這種方法。我認爲處理級聯更新的最簡單的方法就是使用一個客戶端的配置是這樣的:

IClientConfiguration clientConfig = Db4oClientServer.NewClientConfiguration(); 

,然後要麼這些一堆(這不是那麼糟糕,因爲我們可以將屬性添加到每個域實體,然後若有所思地做到這一點上各一個):

clientConfig.Common.ObjectClass(typeof(Application)).CascadeOnUpdate(true); 

或者這樣:

clientConfig.Common.UpdateDepth = 10; 

return Db4oClientServer.OpenClient(clientConfig, databaseServerName, databaseServerPort, databaseUser, databasePassword); 

現在,這裏是服務器的配置,讓我得到透明的持久性的工作。

private void StartDatabase() 
{ 
    IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration(); 

    serverConfiguration.Networking.MessageRecipient = this; 

    serverConfiguration.Common.Add(new TransparentActivationSupport()); 
    serverConfiguration.Common.Add(new TransparentPersistenceSupport()); 

    string db4oDatabasePath  = AppDomain.CurrentDomain.BaseDirectory; 
    string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];    
    int databaseServerPort  = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture); 

    _db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort); 

    string databaseUser  = ConfigurationManager.AppSettings["databaseUser"]; 
    string databasePassword = ConfigurationManager.AppSettings["databasePassword"]; 

    _db4oServer.GrantAccess(databaseUser, databasePassword); 
} 

希望這可以幫助別人。

2

確實,透明持久性需要在每個字段訪問之前調用它的激活器。然而,其意圖是你用enhancer-tool來做到這一點,而不是手動實現。

另一個注意事項:當您在任何地方使用CascadeOnUpdate(true)時,db4o將最終存儲每個可到達的激活對象。如果對象圖很大,這可能是一個主要的性能瓶頸。

0

我在java中使用透明激活和持久性時遇到了同樣的問題。我設法讓它能夠清理數據庫並從頭開始。但是,在更改對象圖之後,通過調用commit()無法工作。您必須在根對象上調用store()。 這是一個簡單的例子:

/*************** Item.java ******************************************/ 
import com.db4o.activation.ActivationPurpose; 
import com.db4o.activation.Activator; 
import com.db4o.collections.ActivatableSupport; 
import com.db4o.ta.Activatable; 

public class Item implements Activatable { 

    private String name; 
    private transient Activator activator; 

    public Item(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     activate(ActivationPurpose.READ); 
     return name; 
    } 

    public void setName(String name) { 
     activate(ActivationPurpose.WRITE); 
     this.name = name; 
    } 

    @Override 
    public String toString() { 
     activate(ActivationPurpose.READ); 
     return "Item [name=" + name + "]"; 
    } 

    public void activate(ActivationPurpose purpose) { 
     ActivatableSupport.activate(this.activator, purpose); 
    } 

    public void bind(Activator activator) { 
     this.activator = ActivatableSupport.validateForBind(this.activator, activator); 
    } 
} 


/******************* Container.java *********************************/ 
import java.util.Set; 
import com.db4o.activation.ActivationPurpose; 
import com.db4o.activation.Activator; 
import com.db4o.collections.ActivatableHashSet; 
import com.db4o.collections.ActivatableSupport; 
import com.db4o.ta.Activatable; 

public class Container implements Activatable { 

    private String name; 
    private Set<Item> items; 
    private transient Activator activator; 

    public Container() { 
     items = new ActivatableHashSet<Item>(); 
    } 

    public String getName() { 
     activate(ActivationPurpose.READ); 
     return name; 
    } 

    public void setName(String name) { 
     activate(ActivationPurpose.WRITE); 
     this.name = name; 
    } 

    public void addItem(Item item) { 
     activate(ActivationPurpose.WRITE); 
     items.add(item); 
    } 
    public Set<Item> getItems() { 
     activate(ActivationPurpose.READ); 
     return items; 
    } 

    @Override 
    public String toString() { 
     activate(ActivationPurpose.READ); 
     return "Container [items=" + items + "]"; 
    } 

    public void activate(ActivationPurpose purpose) { 
     ActivatableSupport.activate(this.activator, purpose); 
    } 

    public void bind(Activator activator) { 
     this.activator = ctivatableSupport.validateForBind(this.activator, activator); 
    } 
} 

/************* Main.java ********************************************/ 
import com.db4o.Db4oEmbedded; 
import com.db4o.ObjectContainer; 
import com.db4o.ObjectSet; 
import com.db4o.config.EmbeddedConfiguration; 
import com.db4o.ta.TransparentActivationSupport; 
import com.db4o.ta.TransparentPersistenceSupport; 

public class Main { 

    public static void main() { 
     EmbeddedConfiguration config = Db4oEmbedded.newConfiguration(); 
     config.common().add(new TransparentActivationSupport()); 
     config.common().add(new TransparentPersistenceSupport()); 
     ObjectContainer db = Db4oEmbedded.openFile(config, System.getProperty("user.home") + "/testTP.db4o"); 

     Container c = new Container(); 
     c.setName("Container0"); 
     ObjectSet<Container> result = db.queryByExample(c); 
     if(result.hasNext()) { 
      c = result.next(); 
      System.out.println(c); 
     } 
     c.addItem(new Item("Item" + c.getItems().size())); 
     db.store(c); 
     System.out.println(c); 
     db.close(); 
    } 
}