Archived

This forum has been archived. Please start a new discussion on GitHub.

Problem: Reading back persistent maps

Hi there!

Q: I'm currently unsuccessfully attempting to read back some persistent values i've stored. Please advise
me on what i'm missing. I get an exception (Microsoft C++ exception: Ice::NoObjectFactoryException @ 0x0012eea8).

I have a map:
StringPersistentUserAccountMap userAccountsMap(dbConnection, "UserAccounts");

filled with entries (4):
...
std::string newName3= "User3";
WGICE::PersistentUserAccountPtr newValue3= new WGICE::PersistentUserAccountI();
newValue1->Set("User3","Pass3","User3@UserGroup.com");
userAccountsMap.insert(make_pair(newName3,newValue3));
...

and an object factory:
class ObjectFactory : public Ice::ObjectFactory
{
public:
virtual Ice::ObjectPtr create(const std::string & type)
{
if(type == "::WGICE::PersistentUserAccount");
return new ::WGICE::PersistentUserAccountI();

assert(false);
}
...
};

and setup the object factory:
ic = Ice::initialize(argc, argv);
ic->addObjectFactory(new ObjectFactory,"::WGICE::PersistentUserAccount");


I fail to get back any of the values:
StringPersistentUserAccountMap::iterator iterator;
for (iterator= userAccountsMap.begin();iterator!= userAccountsMap.end();iterator++)
{
...
std::string value= iterator->first;
...
}

with the following exception (NoObjectFactory):
Eine Ausnahme (erste Chance) bei 0x7c81eb33 in LoginTestServer.exe:
Microsoft C++ exception: Ice::NoObjectFactoryException @ 0x0012eea8.

Regards.

Comments

  • matthew
    matthew NL, Canada
    The sample code looks correct. If you post a complete self-contained example that demonstrates the problem we'll look into it. Alternatively, if you a debug version of Ice available you could put a breakpoint in

    ObjectFactoryPtr
    IceInternal::ObjectFactoryManager::find(const string& id) const

    and see what type Ice is trying to demarshal when reading from the database. You could also dump the contents of the database with dbdump to findout what is actually in there (see the manual for more information on this tool).

    Regards, Matthew
  • Database is not correct, wrong writing code?

    Hi again,
    while dumping the database, I noticed that 3 of the 4 entries are not valid. Do I need some kind of commit or so after each new data entry?

    Command:
    C:\Projects>dumpdb --key string --value ::WGICE::PersistentUserAccount --load C:\Projects\Wiederganger\projects_windows\Interfaces\PersistentUserAccount.ice .\data\userdata_db UserAccounts

    DB Content:
    Key: 'User1'
    Value: class ::WGICE::PersistentUserAccount (object #0)
    {
    mName = 'User1'
    mPassword = 'Pass1'
    mEmail = 'User1@UserGroup.com'
    }
    Key: 'User2'
    Value: class ::WGICE::PersistentUserAccount (object #0)
    {
    mName = ''
    mPassword = ''
    mEmail = ''
    }
    Key: 'User3'
    Value: class ::WGICE::PersistentUserAccount (object #0)
    {
    mName = ''
    mPassword = ''
    mEmail = ''
    }
    Key: 'User4'
    Value: class ::WGICE::PersistentUserAccount (object #0)
    {
    mName = ''
    mPassword = ''
    mEmail = ''
    }

    This was the initial code used to create the entries:
    #ifdef MAKE_USER_ACCOUNTS
    userAccountsMap.clear();

    std::string newName1= "User1";
    WGICE::PersistentUserAccountPtr newValue1= new WGICE::PersistentUserAccountI();
    newValue1->Set("User1","Pass1","User1@UserGroup.com");
    userAccountsMap.insert(make_pair(newName1,newValue1));

    std::string newName2= "User2";
    WGICE::PersistentUserAccountPtr newValue2= new WGICE::PersistentUserAccountI();
    newValue1->Set("User2","Pass2","User2@UserGroup.com");
    userAccountsMap.insert(make_pair(newName2,newValue2));

    std::string newName3= "User3";
    WGICE::PersistentUserAccountPtr newValue3= new WGICE::PersistentUserAccountI();
    newValue1->Set("User3","Pass3","User3@UserGroup.com");
    userAccountsMap.insert(make_pair(newName3,newValue3));

    std::string newName4= "User4";
    WGICE::PersistentUserAccountPtr newValue4= new WGICE::PersistentUserAccountI();
    newValue1->Set("User4","Pass4","User4@UserGroup.com");
    userAccountsMap.insert(make_pair(newName4,newValue4));
    #endif

    Thanks again.
  • benoit
    benoit Rennes, France
    Your code to fill the records is suspicious, you always call "Set" on "newValue1":
    newValue1->Set("User2","Pass2","User2@UserGroup.com");
    newValue1->Set("User3","Pass3","User3@UserGroup.com");
    newValue1->Set("User4","Pass4","User4@UserGroup.com");
    

    I assume you should be calling Set on newValue2, newValue3, newValue4 here instead?

    Note that you should also make sure that you register the object factory with the communicator before to create the map.

    Benoit.
  • bernard
    bernard Jupiter, FL
    Just two clarifications:

    - You need to register class factories before you open a Freeze dictionary (or Evictor) only if you use one or more index, because Freeze/Berkeley DB populates empty indices during opening (and therefore needs to create class objects). In general it's a good idea to always do so, since you may add indices later on.

    - Freeze uses transactions for all write operations. If you don't create a transaction (with connection->beginTransaction()), every single Map write operation (insert, erase, put) is enclosed in its own transaction, so you don't need to worry about committing anything; if you use an iterator for your write operations (for example to erase some entries), then Freeze associates an internal transaction with this iterator and this transaction is committed when the iterator is closed (see the Freeze chapter in the Ice book for details on when Freeze closes iterators).

    Cheers,
    Bernard
  • Update: DB is OK, Read is bad

    Hello again,
    the DB was broken due to the error in assigning values as benoit writes. However, after recreating th DB correctly, accessing the "User3" value gives me a "non rtti object" error as shown below (error occurs in the line with the find code). Before the error occurs, the object factory is called correctly with the right type.

    error:
    (handle.h) Unbehandelte Ausnahme bei 0x7c81eb33 in LoginTestServer.exe: Microsoft C++ exception: __non_rtti_object @ 0x0012edd4.

    code:
    StringPersistentUserAccountMap::const_iterator value= userAccountsMap.find("User3");
    const std::string name= value->first;

    DB data dump:
    Key: 'User3'
    Value: class ::WGICE::PersistentUserAccount (object #0)
    {
    mName = 'User3'
    mPassword = 'Pass3'
    mEmail = 'User3@UserGroup.com'
    }


    I would líke to chew on this problem a bit before I submit a complete sample,but i'm open for tips. I need to understand ICE better.

    Thanks!
  • Update: Error is in line where first is accessed

    FYI,
    the error occurs in the line
    const std::string name= value->first;

    not in the find(...).
  • benoit
    benoit Rennes, France
    Hi,

    Did you compile your code with /GR? See this link for an explanation of the "__non_rtti_object" exception.

    Benoit.
  • Solved! /GR settings on the project level

    Setting /GR on the Visual Studio project level instead of for each file solved the problem for me.

    Thank you!