Understanding Relationships in Realm - PART 2(Many To Many and Inverse Relationship)

in #utopian-io6 years ago

realmDark.jpg

Repository

https://github.com/realm/realm-java

What Will I Learn?

  • You will learn Relationships in Realm
  1. Many To Many Relationship
  2. Inverse Relationship

Requirements

  • An Integrated Development Environment(IDE) for building Android Application(e.g Android Studio, IntelliJ)
  • Android Device/Virtual Device.
  • Little Experience in working with Realm Java.
  • Java Programming Experience.
  • Of course, willingness to learn

Resources

Difficulty

  • Intermediate
Tutorial Duration - 25 - 30Mins

Tutorial Content

In Today's tutorial, we are going to continue learning about relationships in realm database. We are going to basically be looking at two levels of relationships - Many to Many and Inverse Relationships.

The part 1 of this tutorial can be found - here

How Can Relationships be achieved in Realm Database?

Realm lets you define relationships between objects by linking them together, a class becomes a RealmObject is that class extends from the RealmObject class. i.e - public class MyClass extends RealmObject.

In order to explain the relationships, we are going to improve our android application in which the landing page will now have two new buttons, each representing the two relationships.

Next, we will be creating two new fragments which will be representing the relationships and once a user clicks any button, the appropriate fragment will be called.

We would be using the scenario of a Teacher and a Group in which a Teacher in a Many-to-Many relationship will be Many teacher to Many group and in an Inverse Relationship we will be getting the list of Teachers that are associated with a Group.

Outline

  • Add Two new Buttons in our activity_main.xml file.
  • Create Two New Fragments.
  • Edit Our MainActivity.java class file.
  • Create the Necessary Model Classes.
  • Show Relationships in Fragments.

Add Two new Buttons

In our part one of this tutorial, our application only contained two buttons for the one - to - one and the one to many relationship, but in this second part of this tutorial, we will be adding two new buttons to our activity_main.xml file -

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/mainLayout"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        //One to One and One to Many Buttons above

        <Button
            android:id="@+id/manyToMany"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="Many to Many Relationship" />

        <Button
            android:id="@+id/inverseRelationship"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="Inverse Relationship" />

    </LinearLayout>
</RelativeLayout>

In the layout code above, it is important to note that the LinearLayout is displayed in the center of the parent layout which is the RelativeLayout by this line - android:layout_centerInParent="true" and also, all buttons apart from the first button has a margin to their top of 20dp - android:layout_marginTop="20dp".

We have now added two new buttons with the id's - manyToMany,inverseRelationship and with the text - Many to Many Relationship and Inverse Relationship respectively.

Create Two Fragments

We will be creating two new fragments which we will be using to explain the two relationships we will be looking at today.

To create a new blank fragment, right click on your java folder => New => Fragment => Blank Fragment.

BlankFragment1.PNG

Next, Name your fragment - ManyToMany and then do not forget to uncheck the - Include fragment factory methods? and include interface callbacks checkboxes

Many To Many.PNG

Repeat the process for the remaining fragment and make sure to give it a unique name as two fragments can't have the same name.

You can name the remaining fragment - InverseRelatonshipinorder to follow along with the tutorial.

Add Fragment Transactions in MainActivity.java class

Next, in our mainActivity.java we will be using butterknife to inject the onClick methods for our two new buttons and then we will be using FragmentTransaction to call the aappropriate fragment based on the button that was clicked.

To inject the onClick methods of the new buttons using butterknife, place your cursor on the layout name on the setContentView() method and then on windows - alt + ins => Generate ButterKnife Injection and then select the checkboxes shown in the image below:

butterKnife.PNG

Injected Code

The MainActivity.java class file should now look like this

@OnClick({R.id.oneToOne, R.id.oneToMany, R.id.manyToMany, R.id.inverseRelationship})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            //Previous cases

            case R.id.manyToMany:
                showManyToManyFragment();
                break;
            case R.id.inverseRelationship:
                showInverseFragment();
                break;
        }
    }

Note: The showManyToManyFragment(),showInverseFragment()wasn't added by butterknife.

showManyToManyFragment()

private void showManyToManyFragment() {
    ManyToMany manyToMany = new ManyToMany();
    showFragment(manyToMany);
}

In this method, we create a ManyToMany Fragment object and then pass it as an argument to the showFragment() method.

The same step is taken in all the other method - showInverseFragment()

private void showInverseFragment() {
    InverseRelationship inverse = new InverseRelationship();
    showFragment(inverse);
}

showFragment()

private void showFragment(Fragment fragment) {
    FragmentManager  fragmentManager = getFragmentManager();
    FragmentTransaction ft = fragmentManager.beginTransaction();

    ft.replace(R.id.mainLayout,fragment).addToBackStack(fragment.getTag());
    ft.commit();
}

Firstly, we get a FragmentManager object and set it to the getFragmentManger() and then we get a FragmentTransaction object - ft and begin a transaction with it on the FragmentManager object - fragmentManager.

We then call the replace method on the FragmentTransaction object passing the id of the view we want replaced and the the fragment to replace it as the arguments.

Note: The mainLayout id is the id of the RelativeLayout which is the root layout for our activity_main.xml file.

We then add the fragment to backStack using the addToBackStack() method and getting the tag from the fragment as the argument and finally we call commit() on the transaction.

Create the Necessary Model Classes

Many To Many Relationship

To set up a many-to-many relationship, one of the properties of a model will be a type of a RealmObject subclasses:

We will be using our TeacherMany class and our Group class which extends the RealmObject class to show this relationship

TeacherMany.java

public class TeacherMany extends RealmObject {
    public String name;
    public String course;
    public RealmList<Group> groups;
}

The group property is of the type Group which is a RealmObject.

Group.java

public class Group extends RealmObject {
    public String name;
    public int number_of_students;
}

ManyToMany.java

Firstly, we declear a realm object - private Realm realm;.

Inside our onCreate() method just before the return view line we insert the following codes.

To establish the ManyToMany relationship, we create two TeacherMany realm objects and two Group realm objects and then create a many to many relationship between them by by setting the two groups to each of the TeacherMany realm objects.

...

Realm.init(getActivity());
Realm.deleteRealm(Realm.getDefaultConfiguration());

realm = Realm.getDefaultInstance();

realm.beginTransaction();

TeacherMany teacher = realm.createObject(TeacherMany.class);
teacher.name = "Edet Ebenezer";
teacher.course = "Microbiolgy";


TeacherMany teacher2 = realm.createObject(TeacherMany.class);

teacher2.name = "Joseph Ikenna";
teacher2.course = "Computer Science";

Group blue_group = realm.createObject(Group.class);
blue_group.name = "Blue Group";
blue_group.number_of_students = 25;

Group purple_group = realm.createObject(Group.class);
purple_group.name = "Purple Group";
purple_group.number_of_students = 32;

teacher.groups.add(blue_group);
teacher.groups.add(purple_group);

teacher2.groups.add(blue_group);
teacher2.groups.add(purple_group);

realm.commitTransaction();

String toDisplay = teacher.name + " is teaching " + teacher.groups.size() + " Groups Namely - " + teacher.groups.get(0).name + " with " + teacher.groups.get(0).number_of_students + " students"
        + " and " + teacher.groups.get(1).name + " with " + teacher.groups.get(1).number_of_students;

String toDisplay2 = teacher2.name + " is teaching " + teacher2.groups.size() + " Groups Namely - " + teacher2.groups.get(0).name + " with " + teacher2.groups.get(0).number_of_students + " students"
        + " and " + teacher2.groups.get(1).name + " with " + teacher2.groups.get(1).number_of_students;

relationshipManyMany.setText(toDisplay);

relationshipManyMany2.setText(toDisplay2);

...

Code Explanation

First, we initialize the Realm in our fragment, we then start with a clean slate by calling the deleteRealm() method on the defaultConfiguration file.

Next, we begin a realm transaction - realm.beginTransaction() and then we create two Realm object's of the TeacherMany class, we set the name and the course of the first (teacher) - teacher.name = "Edet Ebenezer",eben.course = "Microbioogy" respectively and the second TeacherMany realm object (teacher2) name and course - teacher2.name = "Joseph Ikenna" ,teacher2.course = "Computer Science" respectively.

We then create a two Group object's - blue_group and set its name to "Blue Group" and the number of students to 25 and purple_group and set its name to "Purple Group" and the its number of student property to 32.

We then establish a many-to-many relationship between the two TeacherMany and the Group realm objects by setting two groups to each of the teacher and teacher2 realm objects.

teacher.groups.add(blue_group);
teacher.groups.add(purple_group);

teacher2.groups.add(blue_group);
teacher2.groups.add(purple_group);

Lastly, we concatenate the name of each teachers, the number of groups they are assigned to, the name of the groups and also the number of students in each group in two String variables - toDisplay,toDisplay2.

This is then set as the text of two TextViews in our ManyToMany Fragment layout file - many_to_many_fragment.xml with the id's - relationshipManyMany and relationshipManyMany2 which was injected using Buterknife.

Explanation
  1. We get the teacher's name by teacher.name and the course by teacher.course
  2. We get the size of the groups the teacher is assigned to by -teacher.groups.size() and the name of the group the teacher is assigned to by - teacher.groups.get(0).name for the first group and teacher.groups.get(1).name for the second group and then the number of students by eben.groups.get(0).number_of_students for the first group and eben.groups.get(1).number_of_students for the second group.

NB: You have to edit the layout of your ManyToMany Fragment and input the following which just inserts a two TextView's' to the layout.

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="#FFF"
    android:layout_height="match_parent"
    tools:context=".ManyToMany">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/relationshipManyMany"
        android:text="@string/hello_blank_fragment"
        android:layout_centerInParent="true"
        android:padding="10dp"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/relationshipManyMany2"
        android:text="@string/hello_blank_fragment"
        android:layout_centerInParent="true"
        android:layout_marginTop="20dp"
        android:layout_below="@+id/relationshipManyMany"
        android:padding="10dp"
        />

</RelativeLayout>

Inverse Relationship

In our previous relationships, it is easy for us to follow the link from Teacher to Group but there is no way to go from Group to Teacher object which can be resolved by giving the Group a @LinkingObjects annotation.

So for the Inverse Relationship, we create a new java class file - InverseGroup and extend from the RealmObject class -

public class InverseGroup extends RealmObject {
    public String name;
    public int number_of_students;
    @LinkingObjects("groups")
    public final RealmResults<TeacherInverse> teachers = null;
}

We’ve given InverseGroup a teachers field, and specified that it should contain all TeacherMany objects that have this InverseGroup object in their teachers field.

The annotated field must be declared final and must be of type RealmResults<> where it must hava a type or class of the opposite end of the relationship, one should also note that inverse relationships can result in 0 or 1 or even more objects.

We will also be creating a new java class - TeacherInverse

public class TeacherInverse extends RealmObject {
    public String name;
    public String course;
    public RealmList<InverseGroup> groups;
}

We changed the type of the RealmList to InverseGroup just created above.

InverseRelationship.java

Firstly, we declear a realm object - private Realm realm;.

Inside our onCreate() method just before the return view line we insert the following codes.

...
Realm.init(getActivity());
Realm.deleteRealm(Realm.getDefaultConfiguration());

realm = Realm.getDefaultInstance();

realm.beginTransaction();

TeacherInverse teacher = realm.createObject(TeacherInverse.class);
teacher.name = "Smith Williams";
teacher.course = "French";

TeacherInverse teacher2 = realm.createObject(TeacherInverse.class);

teacher2.name = "Frank Houston";
teacher2.course = "Agriculture";

InverseGroup green_group = realm.createObject(InverseGroup.class);
green_group.name = "Green Group";
green_group.number_of_students = 8;

InverseGroup white_group = realm.createObject(InverseGroup.class);
white_group.name = "White Group";
white_group.number_of_students = 20;

teacher.groups.add(green_group);
teacher.groups.add(white_group);

teacher2.groups.add(green_group);
teacher2.groups.add(white_group);

realm.commitTransaction();

String stringTeacher1 = green_group.name+" has "+green_group.teachers.size()+" teachers - "+ green_group.teachers.get(0).name+" teaching them "+green_group.teachers.get(0).course
        +" and "+green_group.teachers.get(1).name+" teaching them "+green_group.teachers.get(1).course;

String stringTeacher2 = white_group.name+" has "+white_group.teachers.size()+" teachers - "+ white_group.teachers.get(0).name+" teaching them "+white_group.teachers.get(0).course
        +" and "+white_group.teachers.get(1).name+" teaching them "+white_group.teachers.get(1).course;

relationshipInverse.setText(stringTeacher1);

relationshipInverse2.setText(stringTeacher2);
...

Explanation
  1. We get the name of the group by - green_group.name, the number of teachers assgined to the group by - green_group.teachers.size() and then the name of the two teachers of a group by green_group.teachers.get(0).name and green_group.teachers.get(1).name and their courses by green_group.teachers.get(0).course and green_group.teachers.get(1).course
  2. We get the same details as explained above for the second group - white_group.

We then display this details in two TextViews that exist in the layout file of our InverseRelationship Fragment - inverse_relationship_fragment.xml with the id's - relationshipInverse, relationshipInverse2 which was injected using Butterknife

NB: You have to edit the layout of your InverseRelationship Fragment and input the following which just inserts two TextView's' to the layout

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="#FFF"
    android:layout_height="match_parent"
    tools:context=".InverseRelationship">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/relationshipInverse"
        android:text="@string/hello_blank_fragment"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:padding="10dp"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/relationshipInverse2"
        android:text="@string/hello_blank_fragment"
        android:gravity="center_horizontal"
        android:padding="10dp"
        android:layout_below="@+id/relationshipInverse"
        android:layout_marginTop="20dp"
        />

</RelativeLayout>

NB: We have to close the realm database on the onDestroy method of our fragment for both the ManyToMany and InverseRelationship Fragments.

@Override
public void onDestroyView() {
    super.onDestroyView();
    realm.close();
}

Application Execution

Sort:  

Thank you for the contribution! Try to utilize markdowns a bit more for increased readability.

Your contribution has been evaluated according to Utopian rules and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post,Click here


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Thanks @deathwing for moderating my post.
Markdowns will be utilized more in subsequent contributions.

Hey @edetebenezer
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.18
TRX 0.14
JST 0.029
BTC 58132.39
ETH 3138.08
USDT 1.00
SBD 2.44