首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何构造嵌套的一对一关系的实体,以便您可以在Android中获得所有查询?

如何构造嵌套的一对一关系的实体,以便您可以在Android中获得所有查询?
EN

Stack Overflow用户
提问于 2021-04-07 19:21:12
回答 1查看 89关注 0票数 0

我有实体供用户使用。

代码语言:javascript
复制
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?

以下是地址实体:

代码语言:javascript
复制
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实体:

代码语言:javascript
复制
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;
    }
}

这是公司的实体:

代码语言:javascript
复制
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?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-07 21:25:37

首先,我建议更改一些列的名称,使它们成为唯一的,例如

companyName类/实体中的

  • 更改为name

代码语言:javascript
复制
- 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可能是:-

代码语言:javascript
复制
@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,因此只需嵌入所有实体(用户、公司、地址和地理信息)如下:

代码语言:javascript
复制
public class UserWithCompanyWithAddressWithGeo {

    @Embedded
    User user;
    @Embedded
    Company company;
    @Embedded
    Address address;
    @Embedded
    Geo geo;

    public UserWithCompanyWithAddressWithGeo(){}

}

如前所述,查询中的联接将用于构建关系,因此对a/ Dao添加以下内容:

代码语言:javascript
复制
@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()获取所有用户的公司、地址和地理信息。

工作示例

使用上述方法,然后进行以下操作:-

代码语言:javascript
复制
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
        );
    }
}

上面的

  • 只是为了测试而设计的,不是为了重新运行而设计的。
  • 也运行在主线程上,以方便和简洁。

日志中的结果(第一次运行) :-

代码语言:javascript
复制
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-许多关系考虑到已添加到用于测试的活动中的下列内容(在其他插入之后,但在提取之前)

代码语言:javascript
复制
int userx = (int) dao.insertUser(new User("NameX","UserX","EmailX",address1Id,"PhoneX","WebsiteX",company2Id));

  • --这是使用与User1和公司相同的地址(与User2相同)。在

中运行结果

:-

代码语言:javascript
复制
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 :-

代码语言:javascript
复制
public class AddressWithGeo {

    @Embedded
    Address address;
    @Relation(entity = Geo.class,entityColumn = "geoId",parentColumn = "fk_geoId")
    List<Geo> geos;

    public AddressWithGeo(){}
}

第二个(使用->地址和用户->公司)可以是-> :-

代码语言:javascript
复制
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(){}
}

  • ,即用@Embedded @ relationship代替@Embedded@relationship用于低级类,
  • 还注意到,由于AddressWithGeo不是实体而是POJO,所以关系是与Address表.

的关系。

要使用上面的内容,至少需要一个较高级别的Dao @查询。然而,以下是对两者的@查询(从而允许使用Geo提取地址):

代码语言:javascript
复制
@Transaction
@Query("SELECT * FROM address")
List<AddressWithGeo> getAddressWithGeos();
@Transaction
@Query("SELECT * FROM user")
List<UserWithCompanyWithAddressAndGeo> getUserWithCompanyWithAddressAndGeo();

MainActivity中添加了以下内容:

代码语言:javascript
复制
    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);
            }
        }
    }

  • Note循环遍历列表(如果您100%确信至少将存在一个公司、地址和/或Geo,则无需循环遍历列表即可访问元素0)。

连同下列方法(使对日志的写入输出更简单):

代码语言:javascript
复制
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);
}

运行时的结果(除前面的结果外)是:-

代码语言:javascript
复制
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.3
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66992840

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档