使用 Android Room 从 Junction Table 获取数据

Posted

技术标签:

【中文标题】使用 Android Room 从 Junction Table 获取数据【英文标题】:Get data from Junction Table with Android Room 【发布时间】:2020-06-03 16:53:30 【问题描述】:

我目前正在构建一个 android 应用程序,该应用程序显示一个由多个航路点构成的路线。我已经计划好了数据库模式(chen-notation [可能无效的“语法”]):

我尝试重新创建与 android room 的 n-m 关系,但我不知道如何检索联结表 (route_waypoint) 的 index_of_route 属性。

当我得到这样的数据时,我想要联结表属性index_of_route

    @Transaction
    @Query("SELECT * FROM POIRoute")
    List<RouteWithWaypoints> getRoutes();

在 POIWaypoint 类中(可能作为额外属性),或者至少可以从另一个类可以访问,可能是这样实现的:

    @Embedded
    POIWaypoint waypoint;
    int indexOfRoute;

目前我没有从联结表中获得indexOfRoute 属性。

我已经创建的课程:

RouteWithWaypoints:

public class RouteWithWaypoints 

    @Embedded
    private POIRoute poiRoute;

    @Relation(parentColumn = "id",entityColumn = "id",associateBy = @Junction(value = RouteWaypoint.class, parentColumn = "routeId", entityColumn = "waypointId"))
    private List<POIWaypoint> waypoints;

    public POIRoute getPoiRoute() 
        return poiRoute;
    

    public void setPoiRoute(POIRoute poiRoute) 
        this.poiRoute = poiRoute;
    

    public List<POIWaypoint> getWaypoints() 
        return waypoints;
    

    public void setWaypoints(List<POIWaypoint> waypoints) 
        this.waypoints = waypoints;
    

RouteWaypoint:

@Entity(primaryKeys = "waypointId", "routeId", foreignKeys = 
        @ForeignKey(entity = POIWaypoint.class, parentColumns = "id", childColumns = "waypointId"),
        @ForeignKey(entity = POIRoute.class, parentColumns = "id", childColumns = "routeId")
)
public class RouteWaypoint 
    private int waypointId;
    private int routeId;
    
    // I want this attribute inside the POIWaypoint class
    @ColumnInfo(name = "index_of_route")
    private int indexOfRoute;

    public int getWaypointId() 
        return waypointId;
    

    public void setWaypointId(int waypointId) 
        this.waypointId = waypointId;
    

    public int getRouteId() 
        return routeId;
    

    public void setRouteId(int routeId) 
        this.routeId = routeId;
    


POI路线:

@Entity
public class POIRoute

    private String name;
    private String description;
    @PrimaryKey(autoGenerate = true)
    private int id;
    private boolean user_generated;
    private int parentId;


    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getDescription() 
        return description;
    

    public void setDescription(String description) 
        this.description = description;
    

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public boolean isUser_generated() 
        return user_generated;
    

    public void setUser_generated(boolean user_generated) 
        this.user_generated = user_generated;
    

    public int getParentId() 
        return parentId;
    

    public void setParentId(int parentId) 
        this.parentId = parentId;
    



POIWaypoint(请忽略未完成的位置属性):

@Entity
public class POIWaypoint 
    @PrimaryKey(autoGenerate = true)
    private long id;
    @ColumnInfo(name = "long_description")
    private String longDescription;
    private String title;
    @ColumnInfo(name = "short_description")
    private String shortDescription;

    // use converter: https://developer.android.com/training/data-storage/room/referencing-data
    @Ignore
    private GeoPoint position;

    public long getId() 
        return id;
    

    public void setId(long id) 
        this.id = id;
    

    public GeoPoint getPosition() 
        return position;
    

    public void setPosition(GeoPoint position) 
        this.position = position;
    

    public String getTitle() 
        return title;
    

    public void setTitle(String title) 
        this.title = title;
    

    public String getShortDescription() 
        return shortDescription;
    

    public void setShortDescription(String shortDescription) 
        this.shortDescription = shortDescription;
    

    public String getLongDescription() 
        return longDescription;
    

    public void setLongDescription(String longDescription) 
        this.longDescription = longDescription;
    

【问题讨论】:

看来你做得很好。但是你的问题到底是什么?您没有在 RouteWithWaypoints 中获得一些字段,是吗?不清楚 编辑了我的帖子以更具体地说明我的问题和我想要完成的事情。简而言之:目前我无法访问联结表中的index_of_waypoint 属性。在最好的情况下,当我得到一个 RouteWithWaypoints 的实例时,我希望 index_of_waypointPOIWaypoint 类中。 我认为你正在朝着正确的方向前进,你应该在实践中尝试你的想法。但我有一个猜测,因为房间里的关系不是很通用的工具,如果你的想法失败了,你应该记住,你可以用普通的旧 SQL 和循环做你想做的一切) 【参考方案1】:

我通过自己管理关系解决了我的问题。我将 RouteDao 更改为抽象类以插入我自己的方法,该方法自己管理部分联结表:

RouteDao:

 private RouteDatabase database;

    public RouteDao(RouteDatabase database) 
        this.database = database;
    

    @Query("Select * from POIRoute")
    public abstract List<POIRoute> getRoutes();

    @Query("SELECT * FROM POIRoute WHERE id = :id")
    public abstract POIRoute getRoute(int id);

    @Insert
    abstract void insertRouteWithWaypoints(RouteWithWaypoints routeWithWaypoints);

    public List<RouteWithWaypoints> getRoutesWithWaypoints() 
        List<POIRoute> routes = this.getRoutes();
        List<RouteWithWaypoints> routesWithWaypoints = new LinkedList<>();
        for (POIRoute r : routes) 
            routesWithWaypoints.add(new RouteWithWaypoints(r, database.wayPointDao().getWaypointsFromRoute(r.getId())));
        

        return routesWithWaypoints;
    

    public RouteWithWaypoints getRouteWithWaypoints(int id) 
        POIRoute route = this.getRoute(id);
        RouteWithWaypoints routeWithWaypoints = null;
        if (route != null) 
            routeWithWaypoints = new RouteWithWaypoints(route, database.wayPointDao().getWaypointsFromRoute(route.getId()));
        


        return routeWithWaypoints;
    

路点道:

    @Query("SELECT * FROM POIWaypoint")
    POIWaypoint getWaypoints();

    @Query("SELECT * FROM POIWaypoint WHERE id = :id")
    POIWaypoint getWaypoint(long id);

    @Query("SELECT pw.*, rw.index_of_route as 'index' FROM POIWaypoint as pw Join RouteWaypoint as rw on (rw.waypointId = pw.id) where rw.routeId = :id order by 'index' ASC")
    List<POIRouteStep> getWaypointsFromRoute(int id);

【讨论】:

干得好。仍然有一些未来优化的领域,因为您在 getRoutesWithWaypoints 方法中的循环内进行数据库调用(通常这不是最佳选择)。

以上是关于使用 Android Room 从 Junction Table 获取数据的主要内容,如果未能解决你的问题,请参考以下文章

Android Room:使用 Room 插入关系实体

如何使用 Android Room 从数据库中获取一行? [复制]

Android Jetpack 从使用到源码深耕数据库注解Room 从实践到原理

从 SQLite 迁移到 Android Room Persistence Library

如何从 api 获取数据并将数据插入 Android Studio 中的 ROOM(数据库)?

Android Persistence room:“无法弄清楚如何从光标读取此字段”