我有实体供用户使用。
import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.PrimaryKey;
import com.google.gson.annotations.SerializedName;
@Entity(foreignKeys = {
@ForeignKey(entity = Address.class, parentColumns = "addressId", childColumns = "fk_addressId", onDelete = ForeignKey.CASCADE),
@ForeignKey(entity = Company.class, parentColumns = "companyId", childColumns = "fk_companyId", onDelete = ForeignKey.CASCADE)
})
public class User {
@PrimaryKey(autoGenerate = true)
public int userId;
public String name;
public String username;
public String email;
public int fk_addressId;
public String phone;
public String website;
public int fk_companyId;
public User(@NonNull String name, @NonNull String username, @NonNull String email, int fk_addressId,
@NonNull String phone, @NonNull String website, int fk_companyId) {
this.name = name;
this.username = username;
this.email = email;
this.fk_addressId = fk_addressId;
this.phone = phone;
this.website = website;
this.fk_companyId = fk_companyId;
}
}用户有两个外键引用Address和Company实体。这是用户和地址,用户和公司之间的一对一关系。
该地址有一个外键,引用Geo (用于地理定位)。地址和Geo之间有一对一的关系。
我想在一个查询中使用Android中的Room获取用户的地址、Geo和公司信息。
我应该如何构建关系类来做到这一点呢?
在这个链接中有信息:https://developer.android.com/training/data-storage/room/relationships#java
但在这种情况下,用户实体有两个外键,一个是地址,另一个是公司。(地址是指Geo)。
我应该如何构建关系类来获取用户的地址、地理信息和公司信息,在一个查询中使用Android中的Room?
以下是地址实体:
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.PrimaryKey;
import com.google.gson.annotations.SerializedName;
@Entity(foreignKeys = {
@ForeignKey(entity = Geo.class, parentColumns = "geoId", childColumns = "fk_geoId", onDelete = ForeignKey.CASCADE)
})
public class Address {
@PrimaryKey(autoGenerate = true)
public int addressId;
public String street;
public String suite;
public String city;
public String zipCode;
public int fk_geoId;
public Address(@NonNull String street, @NonNull String suite, @NonNull String city,
@NonNull String zipCode, int fk_geoId) {
this.street = street;
this.suite = suite;
this.city = city;
this.zipCode = zipCode;
this.fk_geoId = fk_geoId;
}
}这是Geo实体:
import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class Geo {
@PrimaryKey(autoGenerate = true)
public int geoId;
public double lat;
public double lng;
public Geo(@NonNull double lat, @NonNull double lng) {
this.lat = lat;
this.lng = lng;
}
}这是公司的实体:
import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class Company {
@PrimaryKey(autoGenerate = true)
public int companyId;
public String name;
public String catchPhrase;
public String bs;
public Company(@NonNull String name, @NonNull String catchPhrase, @NonNull String bs) {
this.name = name;
this.catchPhrase = catchPhrase;
this.bs = bs;
}
}我应该如何构建关系类来获取用户的地址、地理信息和公司信息,在一个查询中使用Android中的Room?
发布于 2021-04-07 21:25:37
首先,我建议更改一些列的名称,使它们成为唯一的,例如
将companyName类/实体中的
name- this is to disambiguate it from `name` in the `User` class/entity
- an alternative would be to utilise the `@Embedded`'s `prefix` parameter e.g. `@Embedded(prefix = "cmpny_")` in the POJO used for combining (see UserWithCompanyWithAddressWithGeo below)所以Company可能是:-
@Entity
public class Company {
@PrimaryKey(autoGenerate = true)
public int companyId;
public String companyName;
public String catchPhrase;
public String bs;
public Company(@NonNull String companyName, @NonNull String catchPhrase, @NonNull String bs) {
this.companyName = companyName;
this.catchPhrase = catchPhrase;
this.bs = bs;
}
}其次,对于一对一的关系,您并不需要单独的表,关系的方式可以是1比多(1家公司可以有多个用户,1个地址可以有多个用户,1个geo可以有多个地址)。请参阅答案末尾的附加内容。
接下来,添加一个类(POJO),用于获取所有组合数据,例如UserWithCompanyWithAddressWithGeo。使用此方法,查询中将使用JOINs,因此只需嵌入所有实体(用户、公司、地址和地理信息)如下:
public class UserWithCompanyWithAddressWithGeo {
@Embedded
User user;
@Embedded
Company company;
@Embedded
Address address;
@Embedded
Geo geo;
public UserWithCompanyWithAddressWithGeo(){}
}如前所述,查询中的联接将用于构建关系,因此对a/ Dao添加以下内容:
@Query("SELECT * FROM user JOIN company ON user.fk_companyId = companyId JOIN address ON user.fk_addressId = address.addressId JOIN geo ON address.fk_geoId = geo.geoId")
List<UserWithCompanyWithAddressWithGeo> getUserWithCompanyWithAddressWithGeo();然后,您可以使用getUserWithCompanyWithAddressWithGeo()获取所有用户的公司、地址和地理信息。
工作示例
使用上述方法,然后进行以下操作:-
public class MainActivity extends AppCompatActivity {
final String TAG = "MYDBINFO";
MyDatabase db;
AllDao dao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = Room.databaseBuilder(this,MyDatabase.class,"mydb")
.allowMainThreadQueries()
.build();
dao = db.getAllDao();
int geo1Id = (int) dao.insertGeo(new Geo(52.5,72.3));
int geo2Id = (int) dao.insertGeo(new Geo(33.3,66.6));
int address1Id = (int) dao.insertAddress(new Address("Street1","suite1","city1","1234",geo1Id));
int address2Id = (int) dao.insertAddress(new Address("Street2","Suite2","City2","4321",geo2Id));
int company1Id = (int) dao.insertCompany(new Company("Company1","Catchphrase1","bs1"));
int company2Id = (int) dao.insertCompany(new Company("Company2","Catchphrase2","bs2"));
int user1 = (int) dao.insertUser(new User("Name1","UserName1","Email1",address1Id,"Phone1","Website1",company1Id));
int user2 = (int) dao.insertUser(new User("Name2","UserName2","Email1",address2Id,"Phone2","Website2",company2Id));
List<UserWithCompanyWithAddressWithGeo> userWithCompanyWithAddressWithGeos = dao.getUserWithCompanyWithAddressWithGeo();
for(UserWithCompanyWithAddressWithGeo userWithCompanyWithAddressWithGeo : userWithCompanyWithAddressWithGeos) {
LogUserWithCompanyWithAddress(userWithCompanyWithAddressWithGeo);
}
}
private void LogUserWithCompanyWithAddress(UserWithCompanyWithAddressWithGeo uwcwa) {
Log.d(TAG,
"User-Name = " + uwcwa.user.name +
" User-Email = " + uwcwa.user.email +
"\n\tCompany - Name = " + uwcwa.company.companyName + " Company - Catchphrase = " + uwcwa.company.catchPhrase +
"\n\tAddress - Street = " + uwcwa.address.street + " Address - City = " + uwcwa.address.city +
"\n\t\tGeo - Lat = " + uwcwa.geo.lat + " Geo - Long = " + uwcwa.geo.lng
);
}
}上面的
。
日志中的结果(第一次运行) :-
2021-04-08 06:58:54.635 D/MYDBINFO: User-Name = Name1 User-Email = Email1
Company - Name = Company1 Company - Catchphrase = Catchphrase1
Address - Street = Street1 Address - City = city1
Geo - Lat = 52.5 Geo - Long = 72.3
2021-04-08 06:58:54.636 D/MYDBINFO: User-Name = Name2 User-Email = Email1
Company - Name = Company2 Company - Catchphrase = Catchphrase2
Address - Street = Street2 Address - City = City2
Geo - Lat = 33.3 Geo - Long = 66.6附加
Re 1-许多关系考虑到已添加到用于测试的活动中的下列内容(在其他插入之后,但在提取之前)
int userx = (int) dao.insertUser(new User("NameX","UserX","EmailX",address1Id,"PhoneX","WebsiteX",company2Id));中运行结果
:-
2021-04-08 07:34:59.851 12295-12295/a.a.so66992840javaroomonetoones D/MYDBINFO: User-Name = Name1 User-Email = Email1
Company - Name = Company1 Company - Catchphrase = Catchphrase1
Address - Street = Street1 Address - City = city1
Geo - Lat = 52.5 Geo - Long = 72.3
2021-04-08 07:34:59.851 12295-12295/a.a.so66992840javaroomonetoones D/MYDBINFO: User-Name = Name2 User-Email = Email1
Company - Name = Company2 Company - Catchphrase = Catchphrase2
Address - Street = Street2 Address - City = City2
Geo - Lat = 33.3 Geo - Long = 66.6
2021-04-08 07:34:59.851 12295-12295/a.a.so66992840javaroomonetoones D/MYDBINFO: User-Name = NameX User-Email = EmailX
Company - Name = Company2 Company - Catchphrase = Catchphrase2
Address - Street = Street1 Address - City = city1
Geo - Lat = 52.5 Geo - Long = 72.3替代方法-使用@Relation
当按照最初的方法嵌入实体时,查询需要使用JOIN,但是,您可以避免使用JOIN,并使用@Relation注释来有效地构建JOIN。但是,当使用@Relation时,将检索嵌入实体的列表/数组。
看起来,对于一个3层层次结构(用户->地址- Geo),您需要2级@Relation,因此需要2个POJO类。
第一个(层次结构中最低的)(地址-Geo)可以是AddressWithGeo :-
public class AddressWithGeo {
@Embedded
Address address;
@Relation(entity = Geo.class,entityColumn = "geoId",parentColumn = "fk_geoId")
List<Geo> geos;
public AddressWithGeo(){}
}第二个(使用->地址和用户->公司)可以是-> :-
public class UserWithCompanyWithAddressAndGeo {
@Embedded
User user;
@Relation(entity = Company.class,entityColumn = "companyId",parentColumn = "fk_companyId")
List<Company> company;
@Relation(entity = Address.class,entityColumn = "addressId",parentColumn = "fk_addressId")
List<AddressWithGeo> addressWithGeos;
public UserWithCompanyWithAddressAndGeo(){}
}的关系。
要使用上面的内容,至少需要一个较高级别的Dao @查询。然而,以下是对两者的@查询(从而允许使用Geo提取地址):
@Transaction
@Query("SELECT * FROM address")
List<AddressWithGeo> getAddressWithGeos();
@Transaction
@Query("SELECT * FROM user")
List<UserWithCompanyWithAddressAndGeo> getUserWithCompanyWithAddressAndGeo();在MainActivity中添加了以下内容:
List<AddressWithGeo> addressWithGeos = dao.getAddressWithGeos(); // shows that AddressWithGeo can be used on it's own
List<UserWithCompanyWithAddressAndGeo> userWithCompanyWithAddressAndGeos = dao.getUserWithCompanyWithAddressAndGeo();
for (UserWithCompanyWithAddressAndGeo userWithCompanyWithAddressAndGeo: userWithCompanyWithAddressAndGeos) {
logUser(userWithCompanyWithAddressAndGeo.user);
for(Company cmpny: userWithCompanyWithAddressAndGeo.company) {
logCompany(cmpny);
}
for(AddressWithGeo awg: userWithCompanyWithAddressAndGeo.addressWithGeos) {
logAddress(awg.address);
for(Geo geo: awg.geos) {
logGeo(geo);
}
}
}连同下列方法(使对日志的写入输出更简单):
private void logUser(User usr) {
Log.d(TAG,"Name = " + usr.name + " Username = " + usr.username + " Email = " + usr.email + " Phone = " + usr.phone + " Website = " + usr.website);
}
private void logCompany(Company cmpny) {
Log.d(TAG,"\tName = " + cmpny.companyName + " CatchPhrase = " + cmpny.catchPhrase + " BS = " + cmpny.bs);
}
private void logAddress(Address addr) {
Log.d(TAG,"\tStreet = " + addr.street + " Suite = " + addr.suite + " City = " + addr.city + " Zipcode = " + addr.zipCode);
}
private void logGeo(Geo geo) {
Log.d(TAG,"\t\t Lat = " + geo.lat + " Long = " + geo.lng);
}运行时的结果(除前面的结果外)是:-
2021-04-08 18:26:04.595 D/MYDBINFO: Name = Name1 Username = UserName1 Email = Email1 Phone = Phone1 Website = Website1
2021-04-08 18:26:04.595 D/MYDBINFO: Name = Company1 CatchPhrase = Catchphrase1 BS = bs1
2021-04-08 18:26:04.595 D/MYDBINFO: Street = Street1 Suite = suite1 City = city1 Zipcode = 1234
2021-04-08 18:26:04.595 D/MYDBINFO: Lat = 52.5 Long = 72.3
2021-04-08 18:26:04.595 D/MYDBINFO: Name = Name2 Username = UserName2 Email = Email1 Phone = Phone2 Website = Website2
2021-04-08 18:26:04.595 D/MYDBINFO: Name = Company2 CatchPhrase = Catchphrase2 BS = bs2
2021-04-08 18:26:04.595 D/MYDBINFO: Street = Street2 Suite = Suite2 City = City2 Zipcode = 4321
2021-04-08 18:26:04.596 D/MYDBINFO: Lat = 33.3 Long = 66.6
2021-04-08 18:26:04.596 D/MYDBINFO: Name = NameX Username = UserX Email = EmailX Phone = PhoneX Website = WebsiteX
2021-04-08 18:26:04.596 D/MYDBINFO: Name = Company2 CatchPhrase = Catchphrase2 BS = bs2
2021-04-08 18:26:04.596 D/MYDBINFO: Street = Street1 Suite = suite1 City = city1 Zipcode = 1234
2021-04-08 18:26:04.596 D/MYDBINFO: Lat = 52.5 Long = 72.3https://stackoverflow.com/questions/66992840
复制相似问题