realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.45k stars 1.75k forks source link

Java RealmObject with RealmList property not saved correctly #6642

Closed edujjalvarez closed 4 years ago

edujjalvarez commented 4 years ago

Goal

I try to save data correctly in a model that contains a One to Many relationship (with RealmList).

Actual Results

Please see these images

Result image 1 Result image 2

Steps & Code to Reproduce

ConstructionType RealmObject

[public class ConstructionType extends RealmObject implements IBaseModel {

@Ignore
private static final String TAG = ConstructionType.class.getSimpleName();

/*********************** SPECIFICS ATTRIBUTES AND METHODS ***********************/

private String Name = "";

public String getName() {
    return Name;
}

public void setName(String name) {
    Name = name;
}

private String Description = "";

public String getDescription() {
    return Description;
}

public void setDescription(String description) {
    Description = description;
}

private RealmList<ConstructionSubtype> ConstructionSubtypes;

public RealmList<ConstructionSubtype> getConstructionSubtypes() {
    return ConstructionSubtypes;
}

public void setConstructionSubtypes(RealmList<ConstructionSubtype> constructionSubtypes) {
    ConstructionSubtypes = constructionSubtypes;
}

/********************** BASE MODEL ATTRIBUTES AND METHODS ***********************/

@PrimaryKey
private String Id = UUID.randomUUID().toString();

@Override
public String getId() {
    return this.Id;
}

@Override
public void setId(String id) {
    this.Id = id;
}

private Date RegisterDate = new Date();

@Override
public Date getRegisterDate() {
    return this.RegisterDate;
}

@Override
public void setRegisterDate(Date registerDate) {
    this.RegisterDate = registerDate;
}

private String RegisterBy = "Anonymous";

@Override
public String getRegisterBy() {
    return this.RegisterBy;
}

@Override
public void setRegisterBy(String registerBy) {
    this.RegisterBy = registerBy;
}

private Date UpdatedDate = new Date();

@Override
public Date getUpdatedDate() {
    return this.UpdatedDate;
}

@Override
public void setUpdatedDate(Date updatedDate) {
    this.UpdatedDate = updatedDate;
}

private String UpdatedBy = "Anonymous";

@Override
public String getUpdatedBy() {
    return this.UpdatedBy;
}

@Override
public void setUpdatedBy(String updatedBy) {
    this.UpdatedBy = updatedBy;
}

} ](url)

ConstructionSubtype RealmObject

[public class ConstructionSubtype extends RealmObject implements IBaseModel {

@Ignore
private static final String TAG = ConstructionSubtype.class.getSimpleName();

/*********************** SPECIFICS ATTRIBUTES AND METHODS ***********************/

private String Name = "";

public String getName() {
    return Name;
}

public void setName(String name) {
    Name = name;
}

private String Description = "";

public String getDescription() {
    return Description;
}

public void setDescription(String description) {
    Description = description;
}

/********************** BASE MODEL ATTRIBUTES AND METHODS ***********************/

@PrimaryKey
private String Id = UUID.randomUUID().toString();

@Override
public String getId() {
    return this.Id;
}

@Override
public void setId(String id) {
    this.Id = id;
}

private Date RegisterDate = new Date();

@Override
public Date getRegisterDate() {
    return this.RegisterDate;
}

@Override
public void setRegisterDate(Date registerDate) {
    this.RegisterDate = registerDate;
}

private String RegisterBy = "Anonymous";

@Override
public String getRegisterBy() {
    return this.RegisterBy;
}

@Override
public void setRegisterBy(String registerBy) {
    this.RegisterBy = registerBy;
}

private Date UpdatedDate = new Date();

@Override
public Date getUpdatedDate() {
    return this.UpdatedDate;
}

@Override
public void setUpdatedDate(Date updatedDate) {
    this.UpdatedDate = updatedDate;
}

private String UpdatedBy = "Anonymous";

@Override
public String getUpdatedBy() {
    return this.UpdatedBy;
}

@Override
public void setUpdatedBy(String updatedBy) {
    this.UpdatedBy = updatedBy;
}

}](url)

Api Response

[ { "Id": "6E4254EF-2BC6-456D-89C6-D95ED71CD03C", "Name": "INFRAESTRUCTURA", "Description": null, "ConstructionSubtypes": [ { "Id": "65653C1F-0BF4-4C16-8A15-B7C3E8BB63B4", "Name": "Comisaria", "Description": null }, { "Id": "82837138-108B-4F9B-A447-9C9460AE897B", "Name": "Hospital", "Description": null }, { "Id": "466CCAF7-15EE-46D4-A8B5-2EFDA34DB296", "Name": "Paradas de Colectivo", "Description": null }, { "Id": "8D06C77A-4B82-4083-905A-0D8965218304", "Name": "CAPS", "Description": null }, { "Id": "CA91FE20-C681-4172-8E56-D165EC550CED", "Name": "Centros culturalres recreativos", "Description": null }, { "Id": "59C387E1-38CD-4D28-9F6B-68DD05C29AEF", "Name": "SUM", "Description": null }, { "Id": "F547685E-AC5C-43B5-A60A-265687CC7A30", "Name": "Escuela", "Description": null }, { "Id": "B0BD42EE-63E5-4566-A9DB-0717E33BF302", "Name": "Veredas", "Description": null }, { "Id": "AD284328-8BB2-4467-AD1D-BC345FA58D89", "Name": "Sistema drenaje pluvial", "Description": null }, { "Id": "1B5E3013-5F5E-4E9B-8DE7-12277EB0D2B9", "Name": "Centros deportivos", "Description": null }, { "Id": "5922862B-1223-4EC5-BE6D-DC1C4C272C4A", "Name": "Asalfatado de Calle", "Description": null } ] }, { "Id": "7B26C6CD-E5CA-479C-AFFD-52B5C8B3DEAD", "Name": "VIVIENDA", "Description": null, "ConstructionSubtypes": [ { "Id": "02A73F7F-602E-4F3C-87B7-439C01BB897E", "Name": "Lote con Servicios", "Description": null }, { "Id": "58D1717B-E3B9-4ADF-B8C7-C643F0778693", "Name": "Modulo Santiario", "Description": null }, { "Id": "EEAAAAD1-B68A-42AF-8731-139EE55E82A2", "Name": "Vivienda Progresiva", "Description": null }, { "Id": "551B9E6B-5434-4D59-919A-C45A67ED0270", "Name": "Vivienda definitiva", "Description": null }, { "Id": "15D5BD3A-C7A7-4A3D-AE35-558E9A494196", "Name": "Mejoramiento de vivienda", "Description": null }, { "Id": "7769A01C-F63B-4D0C-991C-80F45D157BCE", "Name": "Cocina", "Description": null }, { "Id": "B87945CF-4E70-4BC1-B2D6-D71507A40C36", "Name": "Vivienda de Emergencia", "Description": null } ] }, { "Id": "7F346D9C-DFCB-4BC2-9EE0-021728750C66", "Name": "SERVICIOS BÁSICOS", "Description": null, "ConstructionSubtypes": [ { "Id": "B25A470F-A51A-4C5C-BF5F-CFD8301FED0D", "Name": "Red de elecricidad", "Description": null }, { "Id": "0484A9C4-FAE6-4BE2-B11B-EF84B7D979D9", "Name": "Red de Cloacas", "Description": null }, { "Id": "58AF6C0F-C8CF-4342-90FD-B186CEAC7130", "Name": "Red de Internet", "Description": null }, { "Id": "66079A41-2A14-4C80-8A00-AEA8AF318F7A", "Name": "Recolección de residuos", "Description": null }, { "Id": "27E18CC2-46D1-4A2A-96DA-D843B5EE637F", "Name": "Red de Agua Potable", "Description": null }, { "Id": "3ACBAAB9-B50B-4948-A171-F5A614FE3C89", "Name": "Red de Gas Natural", "Description": null } ] }, { "Id": "D0A6F6BE-6133-4ECB-8AD1-8A34A137E73B", "Name": "REGULARIZACIÓN DOMINIAL", "Description": null, "ConstructionSubtypes": [ { "Id": "ACF8F281-26AC-44F0-A248-4E73A3E1EE17", "Name": "Planos de Mensura", "Description": null }, { "Id": "3FBDB077-BD1B-499F-9630-26DCF2F9EAD8", "Name": "Entrega de títulos de propiedad", "Description": null }, { "Id": "14AB396B-914A-4601-B7D4-EC1D26AD4339", "Name": "Informe de dominio", "Description": null }, { "Id": "9D7B5DC4-D84E-462B-87C8-ADDBA854ED6C", "Name": "Expropiación", "Description": null }, { "Id": "5173D04E-04FA-4468-B723-1D03473DB43B", "Name": "Entrega de tenencia precaria", "Description": null } ] } ]

Save Function

private String save(List<ConstructionType> constructionTypes) {
        String error = "";
        Realm realm = null;
        try {
            realm = Realm.getDefaultInstance();
            realm.beginTransaction();
            realm.insertOrUpdate(constructionTypes);
            realm.commitTransaction();
        } catch (Exception e) {
            Log.e(TAG, "handleConstructionTypesResponse > error: " + e.getMessage());
            error = "Ocurrió un error insertando/actualizando tipos de obra. Detalle: " + e.getMessage();
        } finally {
            if (realm != null && !realm.isClosed()) realm.close();
        }
        return error;
    }

Version of Realm and tooling

Realm version(s): 5.14.0

Realm Sync feature enabled: No

Android Studio version: 3.5

Android Build Tools version: 29.0.2

Gradle version: 3.5.0

Which Android version and device(s): Android 8.0.0

cmelchior commented 4 years ago

In your example code, your ConstructionSubtypes arrays are all empty, but I don't assume that is the issue?

The key part is how you are mapping from the API response to the Java objects which are sent to save(...). But that code seems to be missing?

edujjalvarez commented 4 years ago

I know what the problem is.

However, this is the code that mapping the API response.

`public void getConstructionTypes(BaseCallback callback) { String url = BuildConfig.TECHOBRAS_BASE_URL + "ConstructionTypes/all"; AndroidNetworking.get(url) .setTag(TAG + "getConstructionTypes") .setPriority(Priority.HIGH) .build() .getAsObjectList(ConstructionType.class, new ParsedRequestListener<List>() { @Override public void onResponse(List results) { Log.d(TAG, "getConstructionTypes> results" + results.size()); if (callback != null) callback.onResults(results); }

                @Override
                public void onError(ANError anError) {
                    Log.e(TAG, "getByUserCode > onError: " + (anError != null ? anError.getMessage() : "Detalle de error no disponible."));
                    if (anError != null) anError.printStackTrace();
                    if (callback != null) callback.onError(anError);
                }
            });
}`
cmelchior commented 4 years ago

Not sure I understand what that code does?

edujjalvarez commented 4 years ago

Not sure I understand what that code does?

I am using the Fast Android Networking library to process requests to the API. Sample here

cmelchior commented 4 years ago

I guess the JSON parser that it uses somehow doesn't work correctly, but why I cannot say.