IOdbExt.GetObjectVersion?

Apr 21, 2013 at 11:52 PM
Edited Apr 21, 2013 at 11:52 PM
NDatabase looks pretty good as an embedded database solution. What does IOdbExt.GetObjectVersion do exactly? It almost sounds like NDatabase stores multiple versions of the object as it changes over time, but I don't see any way to access past versions if that's the case.
Coordinator
Apr 29, 2013 at 7:08 AM
Hello,
NDatabase has some metadata stored internally. The IOdbExt interface allows to read some of them, for objects - creation date, update date, version of it (after updating the object version is changed), or more database specific like database id.

Summarizing, there is no access to older versions of stored object.

Regards,
Jacek
Apr 29, 2013 at 2:08 PM
Is there a way to force NDatabase to store a changed object as an entirely new object?
Coordinator
Apr 29, 2013 at 2:27 PM
Yes, you can retrieve object, close NDatabase, then open it and store retrieved object ;) It will cause that the object will be unknown for NDatabase anymore.

Sample code showing that:
using (var odb = OdbFactory.Open(DbName))
{
    var address = new Address("A", City.Cracow, 1);
    odb.Store(address);
}

Address clonedAddress;
using (var odb = OdbFactory.Open(DbName))
{
    clonedAddress = odb.QueryAndExecute<Address>().GetFirst();
}

using (var odb = OdbFactory.Open(DbName))
{
    odb.Store(clonedAddress);
}

using (var odb = OdbFactory.Open(DbName))
{
    var count = odb.QueryAndExecute<Address>().Count;
    Assert.That(count, Is.EqualTo(2));
}
Apr 29, 2013 at 2:36 PM
Ah yes, that makes sense. Session is gone in the newly opened database. Is database open an expensive operation?
Coordinator
Apr 29, 2013 at 2:50 PM
It depends, but when you are doing short quick things like storing the small object in db, or retrieving 1 object from small db, then it is expensive operation. On the other hand, building index, looking for object without index on huge db, etc - in comparison to such operations it is not expansive one ;)
May 2, 2013 at 6:56 PM
I also have the converse issue: I'd like to replace an object in NDatabase's cache with a clone I made and changed. Currently I'd have to delete the original, then save the new object, but this would likely change the OID. In summary, I think three new IOdb level operations would be very useful:
  1. Detach<T>(T obj): removes an object from the IOdb cache. Thus, load, detach, make some changes, then store would save the original as a new object.
  2. Refresh<T>(T obj): overwrites the in-memory object with the data on disk, ie. refreshes object from persistent state.
  3. Attach<T>(OID id, T obj): replace the object at 'id' in cache and on possibly disk if state differs. If this has an impact on disk storage allocation, you can require that the types be the same.
May 2, 2013 at 6:59 PM
Edited May 2, 2013 at 6:59 PM
Alternately to Detach/Attach, you can provide an overload for Store which takes an OID argument, ie. Store<T>(OID id, T obj). This is perhaps a simpler alternative.
Coordinator
May 2, 2013 at 7:28 PM
Why you cannot just update the object?
May 2, 2013 at 9:02 PM
That's kind of complicated. I'm building a revision control abstraction, and I need the ability to store changed objects under new OIDs, and merge cloned objects into existing OIDs for the fork-join model to work cleanly due to how references may be distributed throughout a program.

In any case, Store<T>(OID id, T obj) seems like a useful generalization of the current store semantics.
Coordinator
May 3, 2013 at 6:00 AM
I think that's okay for your particular usage, but in general case that's breaking of encapsulation.

Why?

OID is the internal mechanism, manipulation on that should be totally hidden from users. I opened the read part of it to the world, but saving OID, changing it etc. still will be the internal mechanism. If someone put new object with existing OID (without knowledge about that), and some stored objects already referenced the old OID, the new object could broke the whole existing object structure.

For previous post -> Detach you have a disconnect method, but still it will rollback the transaction and you need to reopen db. Refresh/Attach are missing the concept of how actually NDatabase is working, manipulation in this way on internal cache is another try to broke encapsulation in mine mind.

I want to keep NDatabase as simple as it could be, especially in the context of API, so I cannot extend it with some particular cases.

I propose for you to use:
  • triggers, for inserting/deleting/updating manipulation
  • updating existing objects
  • creating own layer, to manipulate NDatabase in your way
  • create own fork with customized NDatabase code ;)
Hope it will help,
Jacek
May 3, 2013 at 11:23 AM
If someone put new object with existing OID (without knowledge about that), and some stored objects already referenced the old OID, the new object could broke the whole existing object structure.
Do you have a simple example of what you mean? All the examples I can think of work properly if you replace an old object with a new one of the same type.

Really Store<T>(OID id, T obj) is just exposing a key/value interface for NDatabase.
Coordinator
May 3, 2013 at 8:04 PM
Do you have a simple example of what you mean? All the examples I can think of work properly if you replace an old object with a new one of the same type. ->
agree, but for that case, you could just update the sate of object with new object (Updater class or update method of the object).
May 9, 2013 at 3:30 PM
So in your opinion, a key/value store interface would be best implemented using a separate mechanism from OID, like so:
sealed class Keyed<TKey, TValue>
{
    public TKey Key { get; private set; }
    public TValue Value { get; set; }
}
public static class NDatabaseKV
{
    public static Keyed<TKey, TValue> Get<TKey, TValue>(this IOdb db, TKey key)
    {
        return db.AsQueryable<Keyed<TKey, TValue>>()
                 .SingleOrDefault(x => x.Key.Equals(key));
    }
    public static OID Store<TKey, TValue>(this IOdb db, Keyed<TKey, TValue> kv)
    {
        return db.Store(kv);
    }
}
Coordinator
May 12, 2013 at 4:52 PM
With NDatabase 3.8 it is easier to map OID to your classes (readonly).

Going back - I don't know if that's the best solution, in my opinion it is one of many. You should check how it is updating to yours particular needs, so if it is matching well then give a try ;)

Regerds,
Jacek