Search code examples
c#databasexamarinrealm

Error in Realm Query at (wrapper managed-to-native) Realms.NativeTable.get_string


I'm attempting to do a simple query on my first Realm database. I'm getting an error while trying to access the attributes of an object returned by my query method. I have two questions:
1. What's the meaning of this error? I'm having trouble to understand it...
2. Am I doing the query the right way? If not, what am I doing wrong?

The error log:

[mono-rt] Stacktrace:

[mono-rt]   at <unknown> <0xffffffff>

[mono-rt]   at (wrapper managed-to-native) Realms.NativeTable.get_string >(Realms.TableHandle,intptr,intptr,intptr,intptr,bool&) <0x00057>

[mono-rt]   at Realms.RealmObject.GetStringValue (string) <IL 0x0009d, >0x00323>

[mono-rt]   at EasyVending.RCreditCard.get_holderName () <IL 0x0000e, 0x0006f>

[mono-rt]   at EasyVending.RealmManager.getCreditCard () [0x0001c] in /Users/Bernardo/Projects/EasyVending/EasyVending/DataBase/RealmManager.cs:75

[mono-rt]   at EasyVending.Android.CreditCartManagement.OnCreate (Android.OS.Bundle) [0x00111] in /Users/Bernardo/Projects/EasyVending/EasyVending.Android/Activities/CreditCartManagement.cs:89

[mono-rt]   at Android.Support.V4.App.FragmentActivity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <IL 0x00013, 0x000ff>

[mono-rt]   at (wrapper dynamic-method) object.13add723-97a5-4397-9c8a-e6fc23d98c3c (intptr,intptr,intptr) <IL 0x00017, 0x00043>

[mono-rt]   at (wrapper native-to-managed) object.13add723-97a5-4397-9c8a-e6fc23d98c3c (intptr,intptr,intptr) <IL 0x0001f, 0x00097>

[mono-rt] Attempting native Android stacktrace:

[mono-rt]  at ???+1 [0xbe903ac0]

[mono-rt]  at ???+1 [0x98f50ffc]

=================================================================

Got a SIGSEGV while executing native code. This usually indicates
[mono-rt] a fatal error in the mono runtime or one of the native libraries 
[mono-rt] used by your application.
[mono-rt]

[libc] Fatal signal 11 (SIGSEGV), code 1, fault addr 0x97b77168 in tid 9849 (vending_android)

=====================================

public class RCreditCard : RealmObject {
    public string holderName { get; set; }
    public string bandeira { get; set; }
    public string digitos { get; set; }
    public string token { get; set; }
}

public class RealmManager {
    private string databaseName {
        get {
            return "PayBluDatabase.db";
        }
    }
    private string androidPath {
        get {
            return Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), databaseName);
        }
    }

    public Realm getRealm() {
        return Realm.GetInstance(androidPath);
    }

    public void closeRealm(Realm realm) {
        realm.Close();
    }

    public Transaction insertCreditCard(EasyVending.CreditCard creditCard) {
        var realm = getRealm();
        using(var transaction = realm.BeginWrite()) {
            var insertedCreditCard = realm.CreateObject<RCreditCard>();

            insertedCreditCard.holderName = creditCard.HolderName;
            insertedCreditCard.bandeira = creditCard.CreditCardBrand;
            insertedCreditCard.digitos = creditCard.MaskedCreditCardNumber;
            insertedCreditCard.token = creditCard.InstantBuyKey;

            transaction.Commit();
            closeRealm(realm);
            return transaction;
        }
    }

    public Transaction removeCreditCard() {
        var realm = getRealm();
        using(var transaction = realm.BeginWrite()) {
            realm.RemoveAll<RCreditCard>();
            transaction.Commit();
            closeRealm(realm);
            return transaction;
        }
    }

    public CreditCard getCreditCard() {
        var realm = getRealm();
        var rCreditCard = realm.All<RCreditCard>().First();
        closeRealm(realm);
        var creditCard = new CreditCard() {
            CreditCardBrand = rCreditCard.bandeira,
            MaskedCreditCardNumber = rCreditCard.digitos,
            HolderName = rCreditCard.holderName
        };
        return creditCard;
    }

    public bool hasCreditCard() {
        bool answer = false;
        var realm = getRealm();
        if(realm.All<RCreditCard>().Count() > 0) {
            answer = true;
        }
        closeRealm(realm);
        return answer;
    }
}

The error occurs when I try to access any attribute of the RCreditCard object returned by my query:

CreditCardBrand = rCreditCard.bandeira,

from

var rCreditCard = realm.All<RCreditCard>().First();

Please let me know if the question was not clear enough.


Solution

  • The problem is that you close the realm before you try to read the properties on rCreditCardin getCreditCard(). Properties in Realm objects are zero-copy, they access the database directly, so as soon as you close the realm, the object becomes invalid. We should handle this situation better, it's not clear at the moment. Thank you for pointing it out to us!

    In general, you probably don't want to open and close the realm as often as you do, unless those calls take place on different threads. If you insist on doing this, you should move Realm.Close() calls outside of the transaction using scopes. As it is now, if something throws during the transaction, it will be rolled back but your realm will not be closed like you might expect.

    Finally, having a "normal" class that mirrors your RealmObject class should generally not be necessary. Of course, there may be reasons why it is in your case, that aren't obvious here. Typically, you would use the RealmObject classes directly.