db4o не работает прозрачное постоянство - PullRequest
0 голосов
/ 04 декабря 2011

При использовании клиента / сервера db4o обновления не работают для свойств коллекции объекта.Я использую прозрачную настойчивость, но это не помогает.Затем я изменил свойство Collection на ActivatableCollection, но не повезло.

Это настройка сервера:

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 class Application : ActivatableEntity

И это свойство внутри сущности Application:

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;
}

}

Ответы [ 3 ]

2 голосов
/ 05 декабря 2011

Действительно, прозрачное постоянство требует вызова своего активатора перед каждым доступом к полю. Однако предполагается, что вы делаете это с помощью инструмента Enhancer вместо того, чтобы реализовывать его вручную.

Еще одно примечание: когда вы используете CascadeOnUpdate (true) везде, db4o будет в конечном итоге хранить каждый достижимый активированный объект. Если объект-граф огромен, это может стать проблемой производительности.

0 голосов
/ 03 февраля 2016

У меня была такая же проблема с прозрачной активацией и постоянством в 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();
    }
}
0 голосов
/ 05 декабря 2011

Мне удалось получить прозрачную активацию и настойчивость к работе. Я решил не придерживаться этого подхода по причинам, упомянутым в моем комментарии выше. Я думаю, что самый простой способ обработки каскадных обновлений - это просто использовать конфигурацию клиента, подобную этой:

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);
}

Надеюсь, это кому-нибудь поможет.

...