Извлекать объект в одном сеансе DB4O, сохранять в другом (‘отключенный сценарий’)

#c# #.net #db4o #object-oriented-database #oodb

#c# #.net #db4o #объектно-ориентированная база данных #оодб

Вопрос:

Я пытаюсь выяснить, как сохранить объект пригодным для использования между клиентскими сеансами в DB4O. Насколько я понимаю, после закрытия клиентского сеанса объект больше не находится ни в каком кэше, и, несмотря на то, что у меня есть действительный UUID, я не могу вызвать Store для него, не вызывая вставки дубликата. Я искал способ вручную повторно добавить его в кэш, но такого механизма нет. Повторное извлечение заставит меня скопировать все значения из теперь бесполезного объекта.

Вот приведенный выше абзац в коде:

 Person person = new Person() { FirstName = "Howdoyu", LastName = "Du" };
Db4oUUID uuid;

 // Store the new person in one session
using (IObjectContainer client = server.OpenClient())
{
    client.Store(person);
    uuid = client.Ext().GetObjectInfo(person).GetUUID();
}

// Guy changed his name, it happens
person.FirstName = "Charlie";

using (var client = server.OpenClient())
{
    // TODO: MISSING SOME WAY TO RE-USE UUID HERE

    client.Store(person); // will create a new person, named charlie, instead of changing Mr. Du's first name
}
  

Последняя версия Eloquera поддерживает эти сценарии либо через атрибут [ID], либо через хранилище (uid, object).

Есть мысли?

Ответ №1:

Эта функциональность действительно отсутствует в db4o = (. Это делает db4o очень сложным для использования во многих сценариях.

По сути, вам нужно написать свой собственный метод повторного подключения, перенеся все атрибуты заново. Возможно, библиотека, подобная Automapper, может помочь, но в конце концов вам придется делать это самостоятельно.

Другой вопрос, действительно ли вы хотите использовать UUID db4o для идентификации объекта. UUID db4o огромны и не являются хорошо известным типом. Я лично предпочел бы обычные идентификаторы .NET GUID.

Кстати: существует метод db4o .Bind(), который привязывает объект к существующему идентификатору. Однако это вряд ли делает то, что вы действительно хотите. Я предполагаю, что вы хотите сохранить изменения, внесенные в объект. Привязка в основном заменяет объект и нарушает график объектов. Например, если у вас есть частично загруженные объекты, а затем вы их привязываете, вы теряете ссылки на объекты. Итак .Привязка недоступна.

Комментарии:

1. Спасибо за ответ, я действительно не ожидал решения : ( Это правда, что идентификаторы GUID проще в использовании, и я надеялся использовать их изначально, но я подумал, что если решение действительно существует, оно, скорее всего, использовало бы UUID. Теперь я застрял перед необходимостью выбирать между альтернативным, гораздо менее зрелым OODB или (очень печально) возвращением к толстым рукам ORM.

2. Bind () на самом деле можно использовать в моем конкретном сценарии здесь, где я полностью контролирую доступ к данным, и никакой внешний запрос не может извлекать экземпляры объектов, кроме меня. Я публикую ответ здесь.

Ответ №2:

Хорошо, ответ Gamlor о IExtContainer db4o.Метод Bind () указал мне на решение. Пожалуйста, обратите внимание, что это решение допустимо только в очень специфических ситуациях, когда доступ к базе данных строго контролируется, и никакие внешние запросы не могут получить экземпляры объекта.

Предупреждение: Это решение опасно. Это может заполнить вашу базу данных всевозможными дубликатами и ненужными объектами, потому что это заменяет объект и не обновляет его значения, следовательно, нарушая любые ссылки на него. Нажмите здесь для полного объяснения.

ОБНОВЛЕНИЕ: Даже в жестко контролируемых сценариях это может вызвать бесконечные головные боли (подобные той, с которой я сталкиваюсь сейчас) для чего угодно, кроме плоского объекта, имеющего только свойства типа значения (string, int и т.д.). Если вы не можете разработать свой код для извлечения, редактирования и сохранения объектов в одном соединении db4o, тогда я рекомендую вообще не использовать db4o.

 Person person = new Person() { FirstName = "Charles", LastName = "The Second" };
Db4oUUID uuid;

using (IObjectContainer client = server.OpenClient())
{
    // Store the new object for the first time
    client.Store(person);

    // Keep the UUID for later use
    uuid = client.Ext().GetObjectInfo(person).GetUUID();
}

// Guy changed his name, it happens
person.FirstName = "Lil' Charlie";

using (var client = server.OpenClient())
{
    // Get a reference only (not data) to the stored object (server round trip, but lightweight)
    Person inactiveReference = (Person) client.Ext().GetByUUID(uuid);

    // Get the temp ID for this object within this client session
    long tempID = client.Ext().GetID(inactiveReference);

    // Replace the object the temp ID points to
    client.Ext().Bind(person, tempID);

    // Replace the stored object
    client.Store(person);
}
  

Комментарии:

1. Я просто хочу сказать, что bind заменяет объект и не обновляет его. Это особенно опасно в сложных графиках объектов, поскольку может привести к несоответствиям. Но если это работает для вас, тогда все в порядке.

2. Верно, вот почему я вставил большое предупреждение 🙂

3. Я просто хочу добавить, что извлечение не обязательно выполнять с помощью UUID. Любое другое поле будет работать до тех пор, пока ActivateDepth установлено в 0 на клиенте перед извлечением inactiveReference.