Android Room子查询不匹配字段错误

huangapple go评论65阅读模式
英文:

Android Room Subquery unmatched field error

问题

我无法弄清如何将子查询选择绑定到实体的属性中,我只需将“main_game”子查询绑定到实体的mainGame String属性中。

我的DAO:

@Dao
public interface GamesDao {

        @Query("SELECT *, (SELECT g_nested._id FROM games as g_nested, game_groups as gg WHERE g_nested._id = gg._game_group AND g_nested.is_main = 1 AND gg._game = g._id) as main_game FROM games as g")
    List<GameEntity> getAll();
}

我的GameEntity:

@Entity(tableName = "games")
public class GameEntity extends GenericIndexEntity {

    @NonNull
    @ColumnInfo(name = "gen")
    private Integer gen;

    @NonNull
    @ColumnInfo(name = "is_main")
    private Integer isMain;

    @Ignore
    @ColumnInfo(name = "main_game")
    private String mainGame;

    public GameEntity(@NonNull String indexNumber, String name, String nameEs, String nameIt, String nameFr, String nameDe, String namePt, String nameRu, @NonNull Integer gen, @NonNull Integer isMain, String mainGame) {
        super(indexNumber, name, nameEs, nameIt, nameFr, nameDe, namePt, nameRu);
        this.gen = gen;
        this.isMain = isMain;
        this.mainGame = mainGame;
    }

    @NonNull
    public Integer getGen() {
        return gen;
    }

    public void setGen(@NonNull Integer gen) {
        this.gen = gen;
    }

    @NonNull
    public Integer getIsMain() {
        return isMain;
    }

    public void setIsMain(@NonNull Integer isMain) {
        this.isMain = isMain;
    }

    public String getMainGame() {
        return mainGame;
    }

    public void setMainGame(String mainGame) {
        this.mainGame = mainGame;
    }
}

我尝试过使用@Ignore、@ColumnInfo的多种组合,删除它们,但它似乎无法绑定值。

@Ignore
@ColumnInfo(name = "main_game")
private String mainGame;

这种方式会抛出Tried the following constructors but they failed to match: ... param:mainGame -> matched field:unmatched]

如果我从属性中移除所有标签,查询可以工作,但不会填充值。

我有什么遗漏吗?

英文:

I can't figure out how to bind a subquery select within an attribute of the entity, I simply need to bind the "main_game" subquery into the mainGame String attribute of my entity:

My DAO:

@Dao
public interface GamesDao {
@Query(&quot;SELECT *, (SELECT g_nested._id FROM games as g_nested, game_groups as gg WHERE g_nested._id = gg._game_group AND g_nested.is_main = 1 AND gg._game = g._id) as main_game FROM games as g&quot;)
List&lt;GameEntity&gt; getAll();
}

My GameEntity:

@Entity(tableName = &quot;games&quot;)
public class GameEntity extends GenericIndexEntity {
@NonNull
@ColumnInfo(name = &quot;gen&quot;)
private Integer gen;
@NonNull
@ColumnInfo(name = &quot;is_main&quot;)
private Integer isMain;
@Ignore
@ColumnInfo(name = &quot;main_game&quot;)
private String mainGame;
public GameEntity(@NonNull String indexNumber, String name, String nameEs, String nameIt, String nameFr, String nameDe, String namePt, String nameRu, @NonNull Integer gen, @NonNull Integer isMain, String mainGame) {
super(indexNumber, name, nameEs, nameIt, nameFr, nameDe, namePt, nameRu);
this.gen = gen;
this.isMain = isMain;
this.mainGame = mainGame;
}
@NonNull
public Integer getGen() {
return gen;
}
public void setGen(@NonNull Integer gen) {
this.gen = gen;
}
@NonNull
public Integer getIsMain() {
return isMain;
}
public void setIsMain(@NonNull Integer isMain) {
this.isMain = isMain;
}
public String getMainGame() {
return mainGame;
}
public void setMainGame(String mainGame) {
this.mainGame = mainGame;
}
}

I've tried using multiple combinations of @Ignore, @ColumnInfom removing them but it simply doesn't bind the value:

 @Ignore
@ColumnInfo(name = &quot;main_game&quot;)
private String mainGame;

This way is throwing Tried the following constructors but they failed to match: ... param:mainGame -&gt; matched field:unmatched]

If I remove all the tags from the attribute the query works, but doesn't populate the value.

Am I missing something?

答案1

得分: 1

以下是您请求的翻译内容:

如果您在成员变量上使用@Ignore注解,那么Room会将该成员变量视为一列。如果您不使用@Ignore注解,该成员变量将成为表中的一列。

假设您不希望将成员变量作为表中的一列,但有时需要检索并分配一个值,那么您需要使用一个POJO,该POJO具有一个未被@Ignored注解的成员变量,也许在您的情况下是额外的成员变量(由于扩展类的复杂性)。

另一种方法是硬编码所有成员变量,例如根据类似问题 https://stackoverflow.com/questions/75860588/android-room-additional-constructor-parameter/75861355#comment133938832_75861355 中的回答所述。

由于表的复杂性,即GameEntity扩展了GenericIndexEntity,可能还扩展了其他类,因此硬编码所有涉及的列可能会变成一场噩梦。

因此,您可能希望在POJO中使用@Embedded注解来简化操作。但这样做会包括@Ignore注解的main_game列。因此,您需要使用另一个成员变量。

例如:

public class GameWithMainGamePOJO {
    @Embedded
    GameEntity gameEntity;
    private String mg;

    public void setGameEntity(GameEntity gameEntity) {
        this.gameEntity = gameEntity;
    }

    public String getMg() {
        return mg;
    }

    public void setMg(String mainGame) {
        this.mg = mainGame;
    }

    /* 这可能是您想要的 */
    public GameEntity getGameEntity() {
        gameEntity.setMainGame(this.mg);
        return gameEntity;
    }
}

在这种情况下,您需要输出一个名为mg的列,然后可能使用getGameEntity方法,该方法应返回一个已设置提取值的GameEntity。

演示

以下是基于可用代码的演示,其中还包含其他代码,以及一个查询,用于获取GameEntity列(包括从扩展的GenericIndexEntity继承的列)。

为演示此操作,使用了一个简化的查询,@Dao注解的接口如下:

@Dao
public interface GamesDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long insert(GameEntity gameEntity);
    @Query("SELECT *, (SELECT 'MG1'||g.gen) as mg FROM games as g")
    List<GameWithMainGamePOJO> getAll();
}

完整的演示代码如下(不包括上面的GamesDao接口):

GenericIndexEntity(自拼凑的)

class GenericIndexEntity {
   private String indexNumber;
   private String name;
   private String nameEs;
   // ...
}

**GameEntity**已调整以克服一些未知/猜测):

```java
@Entity(tableName = "games")
public class GameEntity extends GenericIndexEntity {
   @PrimaryKey
   @ColumnInfo(name = "gen")
   private Integer gen;
   @ColumnInfo(name = "is_main")
   private Integer isMain;
   @Ignore
   @ColumnInfo(name = "main_game")
   private String mainGame;
   // ...
}

GameWithMainGamePOJO(如上)

TheDatabase@Database注解的抽象类):

@Database(entities = {GameEntity.class}, exportSchema = false, version = 1)
abstract class TheDatabase extends RoomDatabase {
    abstract GamesDao getGamesDao();
    // ...
}

MainActivity(用于演示原理):

public class MainActivity extends AppCompatActivity {
    TheDatabase db;
    GamesDao dao;
    // ...
}

结果 输出到日志中:

D/DBINFO: IXN = ix1 NAME = G1 NAMEDE = G1DE NAMEES = G1ES NAMEFR = G1FR NAMEIT = G1IT ETC .... MGFROMGE = MG11 MGFROMPOJO =  MG11
D/DBINFO: IXN = ix2 NAME = G2 NAMEDE = G2DE NAMEES = G2ES NAMEFR = G2FR NAMEIT = G2IT ETC .... MGFROMGE = MG12 MGFROMPOJO =  MG12

可以看到MG11/MG12已动态生成并应用,同时getGameEntity方法返回了预期的GameEntity,mainGame也正确设置。

英文:

If you @Ignore a member variable then Room discounts considering that member variable as a column. If you do not @Ignore the member variable it WILL be a column in the table.

Assuming that you do not want the member variable to be a column in the table BUT at some time you want to retrieve and assign a value then you will need to use a POJO that either has a member variable that is not @Ignored perhaps in your case an extra member variable (due to the complexity of extended classes).

Due to the apparent complexity of the table i.e. GameEntity extends GenericIndexEntity and possibly other classes are extended, it would be possibly be a nightmare to hard code all the involved columns.

Thus you may well want to use the @Embedded annotation in the POJO to make life easy. However, doing so will include the @Ignored main_game column. So you would need to use another member variable.

So something like:-

public class GameWithMainGamePOJO {
@Embedded
GameEntity gameEntity;
private String mg;
public void setGameEntity(GameEntity gameEntity) {
this.gameEntity = gameEntity;
}
public String getMg() {
return mg;
}
public void setMg(String mainGame) {
this.mg = mainGame;
}
/* Perhaps what you want */
public GameEntity getGameEntity() {
gameEntity.setMainGame(this.mg);
return gameEntity;
}
}

In which case you would want to output a column named mg and then perhaps use the getGameEntity method which should return a GameEntity with the main_game set with the extracted value.

Demo

Here's a demo based upon the available code, with other code made up and importantly a query that a) gets the GameEntity columns (including the columns from the extended GenericIndexEntity *(my cobbled together version)).

To demo this a simplified query was used, The @Dao annotated interface used being:-

@Dao
public interface GamesDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
long insert(GameEntity gameEntity);
@Query(&quot;SELECT *, (SELECT &#39;MG1&#39;||g.gen) as mg FROM games as g&quot;)
List&lt;GameWithMainGamePOJO&gt; getAll();
}

The full, often cobbled together, code used for the demo (less the GamesDao interface as above):-

GenericIndexEntity (cobbled together)

class GenericIndexEntity {
private String indexNumber;
private String name;
private String nameEs;
private String nameIt;
private String nameFr;
private String nameDe;
private String namePt;
private String nameRu;
GenericIndexEntity(
String indexNumber, String name, String nameEs, String nameIt, String nameFr, String nameDe, String namePt, String nameRu
) {
this.indexNumber = indexNumber;
this.name = name;
this.nameEs = nameEs;
this.nameIt = nameIt;
this.nameFr = nameFr;
this.nameDe = nameDe;
this.namePt = namePt;
this.nameRu = nameRu;
}
public String getIndexNumber() {
return indexNumber;
}
public String getName() {
return name;
}
public String getNameDe() {
return nameDe;
}
public String getNameEs() {
return nameEs;
}
public String getNameFr() {
return nameFr;
}
public String getNameIt() {
return nameIt;
}
public String getNamePt() {
return namePt;
}
public String getNameRu() {
return nameRu;
}
public void setIndexNumber(String indexNumber) {
this.indexNumber = indexNumber;
}
public void setName(String name) {
this.name = name;
}
public void setNameDe(String nameDe) {
this.nameDe = nameDe;
}
public void setNameEs(String nameEs) {
this.nameEs = nameEs;
}
public void setNameFr(String nameFr) {
this.nameFr = nameFr;
}
public void setNameIt(String nameIt) {
this.nameIt = nameIt;
}
public void setNamePt(String namePt) {
this.namePt = namePt;
}
public void setNameRu(String nameRu) {
this.nameRu = nameRu;
}
}

GameEntity (adjusted to overcome some unknowns/guesses):-

@Entity(tableName = &quot;games&quot;)
public class GameEntity extends GenericIndexEntity {
@NonNull
@PrimaryKey
@ColumnInfo(name = &quot;gen&quot;)
private Integer gen;
@NonNull
@ColumnInfo(name = &quot;is_main&quot;)
private Integer isMain;
@Ignore
@ColumnInfo(name = &quot;main_game&quot;)
private String mainGame;
public GameEntity(@NonNull String indexNumber, String name, String nameEs, String nameIt, String nameFr, String nameDe, String namePt, String nameRu){
super(indexNumber,name,nameEs,nameIt,nameFr,nameDe,namePt,nameRu);
}
public GameEntity(@NonNull String indexNumber, String name, String nameEs, String nameIt, String nameFr, String nameDe, String namePt, String nameRu, @NonNull Integer gen, @NonNull Integer isMain, String mainGame) {
super(indexNumber, name, nameEs, nameIt, nameFr, nameDe, namePt, nameRu);
this.gen = gen;
this.isMain = isMain;
this.mainGame = mainGame;
}
@NonNull
public Integer getGen() {
return gen;
}
public void setGen(@NonNull Integer gen) {
this.gen = gen;
}
@NonNull
public Integer getIsMain() {
return isMain;
}
public void setIsMain(@NonNull Integer isMain) {
this.isMain = isMain;
}
public String getMainGame() {
return mainGame;
}
public void setMainGame(String mainGame) {
this.mainGame = mainGame;
}
}

GameWithMainGamePOJO (as above)

TheDatabase the @Database annotated abstract class:-

@Database(entities = {GameEntity.class},exportSchema = false,version = 1)
abstract class TheDatabase extends RoomDatabase {
abstract GamesDao getGamesDao();
private static volatile TheDatabase instance;
public static TheDatabase getInstance(Context context) {
if (instance==null) {
instance= Room.databaseBuilder(context,TheDatabase.class,&quot;the_games_database.db&quot;)
.allowMainThreadQueries() /* for brevity of the demo */
.build();
}
return instance;
}
}

MainActivity to demonstrate the principle:-

public class MainActivity extends AppCompatActivity {
TheDatabase db;
GamesDao dao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = TheDatabase.getInstance(this);
dao = db.getGamesDao();
long g1Id = dao.insert(
new GameEntity(&quot;ix1&quot;,&quot;G1&quot;,&quot;G1ES&quot;,&quot;G1IT&quot;,&quot;G1FR&quot;,&quot;G1DE&quot;,&quot;G1PT&quot;,&quot;G1RU&quot;,1,2,&quot;G1MG&quot;));
GameEntity ge2 = new GameEntity(&quot;ix2&quot;,&quot;G2&quot;,&quot;G2ES&quot;,&quot;G2IT&quot;,&quot;G2FR&quot;,&quot;G2DE&quot;,&quot;G2PT&quot;,&quot;G2RU&quot;);
ge2.setMainGame(&quot;GM2MG&quot;);
ge2.setIsMain(0);
ge2.setGen(2);
long g2id = dao.insert(ge2);
List&lt;GameWithMainGamePOJO&gt; debug = dao.getAll();
for (GameWithMainGamePOJO gwmgpojo: dao.getAll()) {
Log.d(
&quot;DBINFO&quot;,&quot;IXN = &quot; + gwmgpojo.gameEntity.getIndexNumber()
+ &quot;NAME = &quot; + gwmgpojo.gameEntity.getName()
+ &quot;NAMEDE = &quot; + gwmgpojo.gameEntity.getNameDe()
+ &quot;NAMEES = &quot; + gwmgpojo.gameEntity.getNameEs()
+ &quot;NAMEFR   = &quot; + gwmgpojo.gameEntity.getNameFr()
+ &quot;NAMEIT = &quot; + gwmgpojo.gameEntity.getNameIt()
+ &quot; ETC .... &quot;
+ &quot;MGFROMGE = &quot; + (gwmgpojo.getGameEntity()).getMainGame()
+ &quot;MGFROMPOJO =  &quot; + gwmgpojo.getMg()
);
}
}
}

The RESULT output to the log:-

D/DBINFO: IXN = ix1NAME = G1NAMEDE = G1DENAMEES = G1ESNAMEFR   = G1FRNAMEIT = G1IT ETC .... MGFROMGE = MG11MGFROMPOJO =  MG11
D/DBINFO: IXN = ix2NAME = G2NAMEDE = G2DENAMEES = G2ESNAMEFR   = G2FRNAMEIT = G2IT ETC .... MGFROMGE = MG12MGFROMPOJO =  MG12

As can be seen MG11/MG12 has been dynamically generated and applied and also that the getGameEntity method returned the expected HameEntity with mainGame set correctly.

huangapple
  • 本文由 发表于 2023年4月11日 06:28:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75981189.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定