具有复杂 Json 结构的房间

Room with complex Json structure

我是 Room 的新手,目前正在做我的一个项目,我应该在其中插入一些改造 GSON 数据。首先,让我在下面展示我的JSON,这将给出一个清晰的结构。

{
"organization": {
    "id": 0,
    "title": "string",
    "description": "HTML String",
    "style": {
        "navigationBackgroundColor": "#cd1325",
        "navigationTextColor": "#ffffff",
        "topBarLabel": "27July2015abcd",
        "topBarBackgroundColor": "#cd1325",
        "topBarTextColor": "#ffffff",
        "bodyBackgroundColor": "#f5c233",
        "bodyTextColor": "#646363",
        "bannerBackgroundColor": "#ffffff",
        "bannerTextColor": "#000000",
        "buttonBackgroundColor": "#000000",
        "buttonTextColor": "#ffffff",
        "baseTextSize": 0,
        "htmlWrapper": "string"
    }
    "login_options": [{
            "name": "string",
            "title": "EMAIL",
            "description": "string",
            "state": "string",
            "allowed_email_domain": "string",
            "restricted_email_domain": "string"
        }, {
            "name": "string",
            "titl"e: "GOOGLE",
            "description": "string",
            "url": "string",
            "clientId": "string",
            "clientSecret": "string",
            "redirectUri": "string",
            "state": "string",
            "nonce": "string",
            "authorizationEndpointUri": "string",
            "tokenEndpointUri": "string"
        }
    ]
}

}

我正在使用效果很好的改造来解析它。以下是从 https://www.jsonschema2pojo.org/

创建的模型 类 名称

好的。现在我必须通过我的存储库将它们插入到 Room 数据库中,为此我遇到了很多困难。任何人都可以帮助我如何创建实体以及如何将这些数据模型插入​​房间。仍然不确定是将 GSON 模型插入 Room 还是创建实体并将解析数据放入其中然后插入。 我到目前为止所尝试的。

登录选项表

@Parcelize
@Entity
public class LoginOptionsTable {

@ColumnInfo
@PrimaryKey(autoGenerate = true)
public long loginOpnId;

@ColumnInfo(name = "login_options_name")
public String name;

@ColumnInfo(name = "login_options_title")
public String title;

@ColumnInfo(name = "login_options_description")
public String description;

@ColumnInfo
public String state;

@ColumnInfo
public String allowedEmailDomain;

@ColumnInfo
public String restrictedEmailDomain;

@ColumnInfo
public String url;

@ColumnInfo
public String clientId;

@ColumnInfo
public String clientSecret;

@ColumnInfo
public String redirectUri;

@ColumnInfo
public String nonce;

@ColumnInfo
public String authorizationEndpointUri;

@ColumnInfo
public String tokenEndpointUri;

public static List<LoginOptionsTable> fromObject(List<LoginOption> 
mOptions){

    List<LoginOptionsTable> groups = new ArrayList<>();

    for(int i=0; i<mOptions.size(); i++){
        LoginOptionsTable st = new LoginOptionsTable();

        st.name = mOptions.get(i).getName();
        st.title = mOptions.get(i).getTitle();
        st.description = mOptions.get(i).getDescription();
        st.state = mOptions.get(i).getState();
        st.allowedEmailDomain = mOptions.get(i).getAllowedEmailDomain();
        st.restrictedEmailDomain = 
        mOptions.get(i).getRestrictedEmailDomain();
        st.url = mOptions.get(i).getUrl();
        st.clientId = mOptions.get(i).getClientId();
        st.clientSecret = mOptions.get(i).getClientSecret();
        st.redirectUri = mOptions.get(i).getRedirectUri();
        st.nonce = mOptions.get(i).getNonce();
        st.authorizationEndpointUri = 
        mOptions.get(i).getAuthorizationEndpointUri();
        st.tokenEndpointUri = mOptions.get(i).getTokenEndpointUri();

        groups.add(st);
    }


    return groups;
}

}

样式实体:

@Parcelize
@Entity
public class StyleTable {

@ColumnInfo
@PrimaryKey(autoGenerate = true)
public long styleId;

@ColumnInfo
public String navigationBackgroundColor;
@ColumnInfo
public String navigationTextColor;
@ColumnInfo
public String topBarLabel;
@ColumnInfo
public String topBarBackgroundColor;
@ColumnInfo
public String topBarTextColor;
@ColumnInfo
public String bodyBackgroundColor;
@ColumnInfo
public String bodyTextColor;
@ColumnInfo
public String bannerBackgroundColor;
@ColumnInfo
public String bannerTextColor;
@ColumnInfo
public String buttonBackgroundColor;
@ColumnInfo
public String buttonTextColor;
@ColumnInfo
public Integer baseTextSize;
@ColumnInfo
public String htmlWrapper;


public static StyleTable fromObject(Style mStyle) {
    StyleTable st = new StyleTable();

    st.navigationBackgroundColor = mStyle.getNavigationBackgroundColor();
    st.navigationTextColor = mStyle.getNavigationTextColor();
    st.topBarLabel = mStyle.getTopBarLabel();
    st.topBarBackgroundColor = mStyle.getTopBarBackgroundColor();
    st.topBarTextColor = mStyle.getTopBarTextColor();
    st.bannerBackgroundColor = mStyle.getBodyBackgroundColor();
    st.bannerTextColor = mStyle.getBannerTextColor();
    st.buttonBackgroundColor = mStyle.getButtonBackgroundColor();
    st.buttonTextColor = mStyle.getButtonTextColor();
    st.baseTextSize = mStyle.getBaseTextSize();
    st.htmlWrapper = mStyle.getHtmlWrapper();

    return st;
}

}

组织实体:

@Parcelize
@Entity(foreignKeys = {@ForeignKey(entity = StyleTable.class, parentColumns = 
"styleId", childColumns = "stId"),
    @ForeignKey(entity = LoginOptionsTable.class, parentColumns = 
"loginOptionId", childColumns = "loginOpnId")
})
public class OrgTable {

@ColumnInfo
@PrimaryKey
public long id;

@ColumnInfo
public String title;

@ColumnInfo
public String description;

@ColumnInfo
public long stId;

//TODo make it for mutiple table
@ColumnInfo
public Long loginOptionsId;

@Ignore
public StyleTable style;

@Ignore
public List<LoginOptionsTable> loginOptions = null;

public static OrgTable fromObject(Organization organization){
    OrgTable org = new OrgTable();
    org.id = organization.getId();
    org.title = organization.getTitle();
    org.description = organization.getDescription();
    StyleTable st = StyleTable.fromObject(organization.getStyle());
    org.style = st;
    //make the relation through Id
    org.stId = st.styleId;

    List<LoginOptionsTable> lo = 
   LoginOptionsTable.fromObject(organization.getLoginOptions());
    org.loginOptions = lo;
    //make the relation through Id
    org.loginOptionsId = lo.get(0).loginOpnId;


return org;
}

}

DAO

@Dao
public interface OrgDAO {

@Query("SELECT * FROM OrgTable")
OrgTable getOrganization();

@Insert
void insertOrg(OrgTable org);

}

我试图创建这些,但无法理解如何保持这些与 insert/get 保存数据之间的关系。

I have tried to create these, but not able to understand how to keep the relation between these and insert/get the saved data.

您可以通过以下两种方式执行此操作:

  • 一个包含所有三个表的 POJO @Embedded(仅适用于 1 Org -> 1 Login and 1 Style)

  • 带有 OrgTable @Embedded 的 POJO 以及带有 @Relation 注释的 LoginOptionsTable 和 StyleTable

第一个(所有三个表 @Embedded)的示例是:-

class OrgWithLoginAndStyle {

    /* Note use Query that
        JOINS the Orgtable with the Login table
        and JOINS the Orgtable with the Style table
     */

    @Embedded
    OrgTable orgTable;
    @Embedded
    LoginOptionsTable loginOptionsTable;
    @Embedded
    StyleTable styleTable;

}

一个利用这个的 Dao 的例子是:-

@Query("SELECT * FROM OrgTable " +
        "JOIN StyleTable ON StyleTable.styleId = OrgTable.stId " +
        "JOIN LoginOptionsTable ON LoginOptionsTable.loginOpnId = OrgTable.loginOptionsId")
List<OrgWithLoginAndStyle> getOrganizationLoginAndStyle();
  • 这是更灵活的查询方式,因为所有列都可用于 WHERE 子句等,但查询更复杂。

第二个示例(带有对 LoginOptionsTable 和 StyleTable 的 @Relation 注释):-

class OrganizationWithLoginOptionsAndWithStyles {

    @Embedded
    OrgTable orgTable;
    @Relation(entity = LoginOptionsTable.class,parentColumn = "loginOptionsId",entityColumn = "loginOpnId")
    List<LoginOptionsTable> loginOptionsTables;
    @Relation(entity = StyleTable.class,parentColumn = "stId",entityColumn = "styleId")
    List<StyleTable> styleTables;
}
  • 这可能更易于编码。但是,它的效率较低,因为样式和登录选项是为每个 OrgTable 独立检索的。因此,查询更简单,因为您只需要获取 OrgTable(s)。 Room 负责构建相关对象。查询仅限于 OrgTable 列上的 WHERE 等(如果您加入其他表,则此类子句可能不会获得所需的结果(在您的情况下可能没问题,因为每个 OrgTable 对象只有 1 个 LoginOptions 和 1 个 Style))

一个利用这个的 Dao 的例子是:-

@Transaction
@Query("SELECT * FROM OrgTable")
List<OrganizationWithLoginOptionsAndWithStyles> getOrganizationsLoginsAndStyles();
  • 请注意,由于(我相信)基础查询是 运行 获取 LoginOptionsTable 对象和 StyleTable 对象,因此建议使用 @Transaction。

备注 关于您的 getOrganization 查询(见评论)

@Query("SELECT * FROM OrgTable")
//OrgTable getOrganization(); /* <<<<<<<<<< WRONG should be a List */
List<OrgTable> getOrganizations();

还有你的insertOrg

@Insert
//void insertOrg(OrgTable org)
long insertOrg(OrgTable org); /* <<<<<<<<<< might as well allow the id of the inserted row to be obtained */

Ok. Now I have to insert these into the Room database through my repository for which I am facing a lot of difficulties.

而且我相信您的 OrgTable FK 定义应该符合 :-

@Entity(foreignKeys = {@ForeignKey(entity = StyleTable.class, parentColumns =
        "styleId", childColumns = "stId"),
        @ForeignKey(entity = LoginOptionsTable.class, parentColumns =
                "loginOpnId", childColumns = "loginOptionsId")
})
  • 即 LoginOptions child 和 parent 是错误的方式,而且 parent 应该是 loginOptionsId 而不是 loginOptionId(在 Option 之后不是 s)。

基础测试

除了使 OrgDao class :-

之外,使用上面的以下代码
@Dao
public interface OrgDAO {

    @Query("SELECT * FROM OrgTable")
    //OrgTable getOrganization(); /* <<<<<<<<<< WRONG should be a List */
    List<OrgTable> getOrganizations();

    @Query("SELECT * FROM OrgTable " +
            "JOIN StyleTable ON StyleTable.styleId = OrgTable.stId " +
            "JOIN LoginOptionsTable ON LoginOptionsTable.loginOpnId = OrgTable.loginOptionsId")
    List<OrgWithLoginAndStyle> getOrganizationLoginAndStyle();

    @Transaction
    @Query("SELECT * FROM OrgTable")
    List<OrganizationWithLoginOptionsAndWithStyles> getOrganizationsLoginsAndStyles();

    @Insert
    //void insertOrg(OrgTable org)
    long insertOrg(OrgTable org); /* <<<<<<<<<< might as well allow the id of the inserted row to be obtained */

    @Insert
    long insertStyle(StyleTable styleTable);

    @Insert
    long insertLoginOptions(LoginOptionsTable loginOptionsTable);
}

并使用 :-

@Database(entities = {OrgTable.class,StyleTable.class,LoginOptionsTable.class},version = 1) 抽象 class OrgLoginStyleDatabase 扩展 RoomDatabase { 抽象 OrgDAO getOrgDao(); }

还有 activity(请注意,您的一些代码已被注释掉,即使用 @Parcelize 和实体的 @Ignored Constructors):-

public class MainActivity extends AppCompatActivity {

    OrgLoginStyleDatabase db;
    OrgDAO dao;
    public static final String TAG = "OLSINFO";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = Room.databaseBuilder(this,OrgLoginStyleDatabase.class,"orgloginoptionsstyle.db")
                .allowMainThreadQueries()
                .build();
        dao = db.getOrgDao();

        StyleTable s1 = new StyleTable();
        s1.bannerBackgroundColor = "X";
        s1.bannerTextColor = "X";
        s1.baseTextSize = 20;
        s1.bodyBackgroundColor = "X";
        s1.bodyTextColor = "X";
        s1.buttonBackgroundColor = "X";
        s1.buttonTextColor = "X";
        s1.htmlWrapper = "X";
        s1.navigationBackgroundColor = "X";
        s1.navigationTextColor = "X";
        s1.styleId = 100;
        s1.topBarBackgroundColor = "X";
        s1.topBarLabel = "X";
        s1.topBarTextColor = "X";
        long s1Id = dao.insertStyle(s1);
        LoginOptionsTable l1 = new LoginOptionsTable();
        l1.allowedEmailDomain = "Y";
        l1.authorizationEndpointUri = "Y";
        l1.clientId = "Y";
        l1.clientSecret = "Y";
        l1.description = "Y";
        l1.loginOpnId = 1000;
        l1.name = "Y";
        l1.nonce = "Y";
        l1.redirectUri = "Y";
        l1.restrictedEmailDomain = "Y";
        l1.state = "Y";
        l1.title = "Y";
        l1.url = "Y";
        long l1Id = dao.insertLoginOptions(l1);
        OrgTable o1 = new OrgTable();
        o1.description = "Z";
        o1.id = 10000;
        o1.loginOptionsId = l1Id;
        o1.stId = s1Id;
        dao.insertOrg(o1);
        List<OrgTable> orgTableList = dao.getOrganizations();
        for(OrgTable o: orgTableList) {
            logOrgTable(o,"FROM getOrganizations -> ");
        }
        List<OrganizationWithLoginOptionsAndWithStyles> organizationsLoginsAndStylesList = dao.getOrganizationsLoginsAndStyles();
        for(OrganizationWithLoginOptionsAndWithStyles owloaws: organizationsLoginsAndStylesList) {
            logOrgTable(owloaws.orgTable,"FROM (@Relations) getOrganizationsLoginsAndStyles -> ");
            for(LoginOptionsTable lot: owloaws.loginOptionsTables) {
                logLoginOptionsTable(lot,"\t");
            }
            for(StyleTable s: owloaws.styleTables) {
                logStyleTable(s,"\t");
            }
        }
        List<OrgWithLoginAndStyle> owlas = dao.getOrganizationLoginAndStyle();
        for(OrgWithLoginAndStyle o: owlas) {
            logOrgTable(o.orgTable,"FROM (@Embeddeds) getOrganizationLoginAndStyle -> ");
            logLoginOptionsTable(o.loginOptionsTable,"\t");
            logStyleTable(o.styleTable,"\t");
        }
    }

    private void logOrgTable(OrgTable o,String preamble) {
        Log.d(TAG,preamble + "OrgTable Description = " + o.description + " ID = " + o.id);
    }
    private void logStyleTable(StyleTable s, String preamble) {
        Log.d(TAG,preamble + "StyleTable Description = " + s.topBarTextColor + " ID =" + s.styleId);
    }
    private void logLoginOptionsTable(LoginOptionsTable l, String preamble) {
        Log.d(TAG,preamble + "LoginOptionsTable Description = " + l.description + " ID = " + l.loginOpnId);
    }
}

结果

当运行时(只会运行曾经使用过的硬编码ID)输出到日志的结果是:-

2021-04-12 21:51:50.981 D/OLSINFO: FROM getOrganizations -> OrgTable Description = Z ID = 10000

2021-04-12 21:51:50.987 D/OLSINFO: FROM (@Relations) getOrganizationsLoginsAndStyles -> OrgTable Description = Z ID = 10000
2021-04-12 21:51:50.987 D/OLSINFO:  LoginOptionsTable Description = Y ID = 1000
2021-04-12 21:51:50.987 D/OLSINFO:  StyleTable Description = X ID =100

2021-04-12 21:51:50.989 D/OLSINFO: FROM (@Embeddeds) getOrganizationLoginAndStyle -> OrgTable Description = Z ID = 10000
2021-04-12 21:51:50.989 D/OLSINFO:  LoginOptionsTable Description = Y ID = 1000
2021-04-12 21:51:50.989 D/OLSINFO:  StyleTable Description = X ID =100
  • 所有三个对象都已成功插入,所有三个查询都按预期工作。