Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Room insert "one-to-many" relation

I want to handle "one-to-many" relation using Android Room. I easily can fetch related entities using @Relation[1]. According to [2][3], there isn't native support for @Relation insert in Room. In [3][4] relation is created manually (IDs are set manually for "one" object and related "many" objects). However, I prefer to use Autoincrement PK as id(I access to "one" object by its name(String)).

Is there "elegant way" to insert related entities("one-to-many") with Autoincrement PK?

Links

  1. https://developer.android.com/reference/android/arch/persistence/room/Relation
  2. Android Room: Insert relation entities using Room
  3. https://issuetracker.google.com/issues/62848977
  4. https://android.jlelse.eu/android-architecture-components-room-relationships-bf473510c14a
like image 863
relativizt Avatar asked Feb 04 '23 21:02

relativizt


1 Answers

I found that @Insert method can return a long, which is the new rowId for the inserted item[1].

If the @Insert method receives only 1 parameter, it can return a long, which is the new rowId for the inserted item. If the parameter is an array or a collection, it should return long[] or List instead.

And SQLite documentation[2] says:

If a table contains a column of type INTEGER PRIMARY KEY, then that column becomes an alias for the ROWID. You can then access the ROWID using any of four different names, the original three names described above or the name given to the INTEGER PRIMARY KEY column. All these names are aliases for one another and work equally well in any context.

So we can make:

1) CompanyEntity.java

@Entity(tableName = "companies", indices = @Index(value = "name", unique = true)) public class CompanyEntity {
    @PrimaryKey (autoGenerate = true)
    public int id;
    @NonNull
    @ColumnInfo(name = "name")
    private final String mCompanyName;

    public CompanyEntity(@NonNull String companyName) {
        mCompanyName = companyName;
    }

    @NonNull
    public String getCompanyName() {
        return mCompanyName;
    }
}

2) EmployeeEntity.java

@Entity(tableName = "employee_list",
        foreignKeys = @ForeignKey(
                entity = CompanyEntity.class,
                parentColumns = "id",
                childColumns = "company_id",
                onDelete = CASCADE),
        indices = @Index("company_id"))
public class EmployeeEntity {
    @PrimaryKey(autoGenerate = true)
    public int id;
    @ColumnInfo(name = "company_id")
    private long mCompanyId;
    @NonNull
    @ColumnInfo(name = "name")
    private final String mName;

    public EmployeeEntity(@NonNull String name) {
        mName = name;
    }

    @NonNull
    public String getName() {
        return mName;
    }

    public long getCompanyId() {
        return mCompanyId;
    }

    public void setCompanyId(long companyId) {
        mCompanyId = companyId;
    }
}

3) EmployeeDao.java

@Dao
public abstract class EmployeeDao {

    @Query("SELECT * FROM companies")
    public abstract List<CompanyEntity> selectAllCompanies();

    @Transaction
    @Query("SELECT * FROM companies WHERE name LIKE :companyName")
    public abstract List<CompanyEmployees> getEmployeesByCompanyName(String companyName);

    @Transaction
    public void insert(CompanyEntity companyEntity, List<EmployeeEntity> employeeEntities) {

        // Save rowId of inserted CompanyEntity as companyId
        final long companyId = insert(companyEntity);

        // Set companyId for all related employeeEntities
        for (EmployeeEntity employeeEntity : employeeEntities) {
            employeeEntity.setCompanyId(companyId);
            insert(employeeEntity);
        }

    }

    // If the @Insert method receives only 1 parameter, it can return a long,
    // which is the new rowId for the inserted item.
    // https://developer.android.com/training/data-storage/room/accessing-data
    @Insert(onConflict = REPLACE)
    public abstract long insert(CompanyEntity company);

    @Insert
    public abstract void insert(EmployeeEntity employee);

}

It seems to work fine.

Full source code and example project: https://github.com/relativizt/android-room-one-to-many-auto-pk

Links

  1. https://developer.android.com/training/data-storage/room/accessing-data
  2. https://www.sqlite.org/autoinc.html
like image 174
relativizt Avatar answered Feb 06 '23 16:02

relativizt