I have two objects: MailBox and Email. Each Receiver has many Emails.
public class MailBoxRealmModel extends RealmObject {
#PrimaryKey
private long id;
private String name;
private String mailboxId;
private RealmList<EmailRealmModel> emails;
}
public class EmailRealmModel extends RealmObject {
#PrimaryKey
private long EmailId;
private String Name;
private String Text;
private String Tag;
private int Type;
private String Time;
private int Status;
}
How can one use **realm.insertOrUpdate**when adding email to MailBoxRealmModel?
EmailRealmModel email = new EmailRealmModel();
email.setMessageId(emailID);
realm.insertOrUpdate(email );
mailBoxRealmModel.getEmails().add(email);
I am getting a null pointer exception email on this line:
mailBoxRealmModel.getEmails().add(email);
Exception:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean io.realm.RealmList.add(io.realm.RealmModel)' on a null object reference
at com.koa.mailbox.MailBoxActivity$1.execute(MailBoxActivity.java:123)
at io.realm.Realm.executeTransaction(Realm.java:1253)
at com.koa.mailbox.MailBoxActivity.test(MailBoxActivity.java:88)
at com.koa.mailbox.MailBoxActivity.onCreate(MailBoxActivity.java:71)
at android.app.Activity.performCreate(Activity.java:6876)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)
at android.app.ActivityThread.access$1100(ActivityThread.java:222)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
Proper way to create a new RealmObject with existing primary key is usage realm.createObject(EmailRealmModel.class, emailID)method.
Full code fragment:
realm.beginTransaction();
EmailRealmModel email = realm.createObject(EmailRealmModel.class, emailID);
mailBoxRealmModel.getEmails().add(email);
realm.commitTransaction();
Or, if you wish update stored in realm object using one of inmemory instances, you should call realm.copyToRealmOrUpdate(obj).
Example from documentation:
// For create managed proxy, you should wrap EmailRealmModel object by call copyToRealmXXX
EmailRealmModel email = realm.copyToRealmOrUpdate(new EmailRealmModel(id));
mailBoxRealmModel.getEmails().add(email);
On an unmanaged RealmObject, the RealmList fields must be initialized manually.
EmailRealmModel email = new EmailRealmModel();
email.setMessageId(emailID);
mailBoxRealmModel.setEmails(new RealmList<MailBoxRealmModel>());
mailBoxRealmModel.getEmails().add(email);
realm.insertOrUpdate(mailBoxRealmModel);
Related
This question already has answers here:
Cannot retrieve field values from realm object, values are null in debugger
(5 answers)
Closed 5 years ago.
I need to do a simple query in Realm, retrieve a list of MyModel object and later use it somewhere else in my app. It happens that once I query Realm, each object has null values, but the toString returns the expected values.
Model:
#RealmClass
public class MyModel extends RealmObject implements Serializable {
public static final String KEY_MODEL = "key_myModel";
#PrimaryKey
private int id;
private String myStr;
private int myInt;
//.... getters and setters
#Override
public String toString() {
return "id = " + id
+ "\nmyStr = " + myStr
+ "\nmyInt = " + myInt;
}
}
How do I store the value:
public static void storeModel(MyModel model) {
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
realm.copyToRealm(model);
realm.commitTransaction();
}
How do I retrieve the objects:
public static RealmList<MyModel> getNewElementsFromIndex(int indexFrom) {
Realm realm = Realm.getDefaultInstance();
RealmResults<MyModel> allValues = realm.where(MyModel).greaterThan("id", indexFrom).findAll();
RealmList<MyModel> finalList = new RealmList<MyModel>();
finalList.addAll(allValues.subList(0, allValues.size()));
return finalList;
}
When i call getNewElementsFromIndex(value) i get a list of item, but all items in this list have the parameter myStr = null and myInt = 0.
What am I doing wrong?
For managed realm objects, data is not copied to the fields, you obtain them through the proxy getter/setter calls.
Therefore, the fact that fields are null and toString() shows the values is completely expected and well-documented behavior.
To see the values, you have to add watches for the getter methods.
See the documentation.
Why is this code triggering a
java.lang.IllegalArgumentException: RealmObject is not valid, so it cannot be copied
error?
realm.beginTransaction();
realm.delete(Booking.class);
final Booking booking = realm.copyFromRealm(
new Booking(
editFragment.getDestination(),
editFragment.getDate()));
realm.commitTransaction();
However, if I change it to this the exception is not thrown:
realm.delete(Booking.class);
final Booking booking = realm.createObject(
Booking.class,
UUID.randomUUID().toString());
booking.setDestination(editFragment.getDestination());
booking.setDate(editFragment.getDate());
What is the difference?
The Booking class is defined as:
public class Booking extends RealmObject {
#Required
#PrimaryKey
private String id;
#Required
private String destination;
#Required
private Date date;
private int status;
private boolean isNotified;
public Booking() {
this.id = UUID.randomUUID().toString();
this.status = STATUS_UNAVAILABLE;
}
public Booking(String destination, Date date) {
this();
this.destination = destination;
this.date = date;
}
// Getters and setters follow
}
Edit:
Found what was wrong: I accidentally used copyFromRealm instead of copyToRealm. Looks like autocomplete sometimes works against you if you are not careful enough haha.
You have to pass a valid RealmObject into copyFromRealm(..) It is not sufficient to create a new instance on the fly, because the new object won't be attached to Realm.
Makes a standalone in-memory copy of an already persisted {#link RealmObject}.
In your second example you are creating a new object and passing it to the DB to be persisted: that are two very different operations.
Realm not saving (or possibly not returning) String values of related object...
i have 3 models:
public class Customer extends RealmObject {
#Expose
#PrimaryKey
private Long id;
#Expose
private Long historicalId;
#Expose
private String versionUUID;
#Expose
private String nameCompany;
#Expose
private String email;
#Expose
private String phoneNumber;
#Expose
private String notes;
#Expose
private boolean active;
#Expose
private boolean currentVersion;
#Expose
private Date lastUpdated;
#Expose
private Date dateCreated;
public Customer() {
}
and
public class Project extends RealmObject {
#PrimaryKey
private Long id;
private Long historicalId;
private String versionUUID;
private String name;
private String description;
private String addressLineOne;
private String addressLineTwo;
private String addressCity;
private String addressState;
private String addressZip;
private String notes;
private Date lastUpdated;
private Date dateCreated;
private boolean active;
private boolean currentVersion;
private Customer customer;
private String customerVersion;
public Project() {
}
and lastly (added for the comment question)
public class Receipt extends RealmObject {
#PrimaryKey
private String id;
private String name;
private String vendor;
private Double amount;
private String description;
private Date dateCreated;
private Date lastUpdated;
private Date dateSynced;
private byte[] imageByteArray;
private Project project;
private String projectVersion;
private int imgWidht;
private int imgHeight;
public Receipt() {
}
i am saving the data via:
public static void syncAllDataToRealm(Context context){
Globals globals = Globals.getInstance();
Realm realm = Realm.getInstance(context);
realm.beginTransaction();
realm.copyToRealmOrUpdate(globals.getAllCustomers());
realm.copyToRealmOrUpdate(globals.getAllProjects());
realm.commitTransaction();
testRealCommit(context);
}
and i am verifying the data via
private static void testRealCommit(Context context){
Realm realm = Realm.getInstance(context);
RealmQuery<Customer> customerRealmQuery = realm.where(Customer.class);
RealmResults<Customer> customerRealmResults = customerRealmQuery.findAll();
logger.debug(LogUtility.generateMessage(TAG, "===== CUSTOMER ======= "));
for(Customer c: customerRealmResults){
logger.debug(LogUtility.generateMessage(TAG, c.getId() + " - " + c.getNameCompany()));
}
logger.debug(LogUtility.generateMessage(TAG, "===== CUSTOMER GLOBAL======= "));
for(Customer c: Globals.getInstance().getAllCustomers()){
logger.debug(LogUtility.generateMessage(TAG, c.getId() + " - " + c.getNameCompany()));
}
RealmQuery<Project> projectRealmQuery = realm.where(Project.class);
RealmResults<Project> projectRealmResults = projectRealmQuery.findAll();
logger.debug(LogUtility.generateMessage(TAG, "===== PROJECT ======="));
for(Project p: projectRealmResults){
logger.debug(LogUtility.generateMessage(TAG, p.getId() + " - " + p.getName()));
}
}
for some reason:
c.getNameCompany()
returns a null in the above code... if i dont add the project data to realm it works fine....
realm is bein set up in my Application file via:
RealmConfiguration config = new RealmConfiguration.Builder(context)
.name("receiptbucket.realm")
.schemaVersion(2)
.build();
Realm.setDefaultConfiguration(config);
any ideas???
found out something else... if i swap the commit order, adding all customers after adding all projects it works
realm.copyToRealmOrUpdate(globals.getAllProjects());
realm.copyToRealmOrUpdate(globals.getAllCustomers());
short term fix but i would like to know why i have to do it this way for the customer data to stick...
(New Issue)
now when i call copyOrUpdate for the Receipt it wipes all the customer data Projects Customer....
From your last description, I think the problem is the Project list returned by globals.getAllProjects() contains some Customer which has null value for nameCompany .
The reason is your Customer class has an id which is annotated with #PrimaryKey, when realm.copyToRealmOrUpdate(globals.getAllProjects()) called, Realm will create or update related objects recursively. (That is the whole point of update here).
If it finds a customer which has the same id and already saved in the Realm, it will just use all new values from Project.customer to update the one existed in the Realm. If the Procject.customer.nameCompany is null, you will have the problem you described above.
The solution would be make the globals.getAllProjects() return the latest value you want to update, since there is no way for Realm to understand whether the null values are something you want to ignore or update to.
i was able to overcome the last error by querying realm and reattaching the Customer that was getting nulled out to the Project which is part of the Receipt....
so then i started playing.... I was loading realm from Global data... I stopped that and loaded realm right when i got the data from my rest service...
upon doing that everything started just working correctly, lol...
I'm using realm to store my data on Android. Awesome framework! Now the only problem I'm now having is:
I got a array list strings with id's of Countries in my database.
Now I retrieve my Drinks that contains a relationship to countries.
Is there a way that I could to do a query like this:
String [] ids;
realm.where(Drinks.class).equalsTo("country.id", ids);
Something like that?
Or do I really need to do a query to get me all drinks and then filter the list manually?
EDIT:
My classes:
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private Country country;
}
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
}
What you want to do is possible with link queries in theory (searching for "country.id"), however link queries are slow. Also you'd need to concatenate a bunch of or() predicates together, and I would not risk that with a link query.
I would recommend using the following
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private Country country;
#Index
private String countryId;
}
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
}
And when you set the Country in your class, you also set the countryId as country.getId().
Once you do that, you can construct such:
RealmQuery<Drinks> drinkQuery = realm.where(Drinks.class);
int i = 0;
for(String id : ids) {
if(i != 0) {
drinkQuery = drinkQuery.or();
}
drinkQuery = drinkQuery.equalTo("countryId", id);
i++;
}
return drinkQuery.findAll();
Since the Realm database has added RealmQuery.in() with the version 1.2.0
I suggest using something like this.
//Drinks
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private String countryId;
//getter and setter methods
}
//Country
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
//getter and setter methods
}
The code to use inside activity/fragments to retrieve drink list
String[] countryIdArray = new String[] {"1","2","3"} //your string array
RealmQuery<Drinks> realmQuery = realm.where(Drinks.class)
.in("countryId",countryIdArray);
RealmResults<Drinks> drinkList = realmQuery.findAll();
In latest version of Realm 7+, you can use anyOf to match a field against a list of values.
anyOf("name", new String[]{"Jill", "William", "Trillian"})
in older versions, use in instead of anyOf and with kotlin use oneOf instead of in.
see this issue
To match a field against a list of values, use in. For example, to find the names “Jill,” “William,” or “Trillian”, you can use in("name", new String[]{"Jill", "William", "Trillian"}). The in predicate is applicable to strings, binary data, and numeric fields (including dates).
Doc.-> https://realm.io/docs/java/latest#queries
I am pretty much aware of the absence of foreign keys in Realm. But I encountered this issue. I receive data in a normalised way and I have to figure out how to properly persist the relations.
Example:
class User{
private int id;
private Email email;
}
class Email{
private int id;
private String address;
}
And I receive something like:
{user={id:1, emailId:1}}
How can I store this type of data in my existing realm object ?
You will have to parse the JSON yourself to setup the links. From your description it isn't clear if you User and Email is already in Realm, but if that is the case I would do something like this:
class User{
#PrimaryKey
private int id;
private Email email;
}
class Email{
#PrimaryKey
private int id;
private String address;
}
JSONObject json = new JSONObject("{id:1, emailId:1}");
realm.beginTransaction();
User user = realm.where(User.class).equalTo("id", json.getInt("id")).findFirst();
Email email = realm.where(Email.class).equalTo("id", json.getInt("emailId")).findFirst();
user.setEmail(email);
realm.commitTransaction();