【问题标题】:Problems with ORMLite and lazy collectionsORMLite 和惰性集合的问题
【发布时间】:2011-11-06 17:27:39
【问题描述】:

我在我的 android 项目中使用 ormlite。我有两节课

@DatabaseTable(tableName = "usershows")
public class UserShow {
    @DatabaseField(id = true)
    private Integer showId;

    @ForeignCollectionField(eager = false)
    private ForeignCollection<Episode> episodes;
    ...
}

@DatabaseTable(tableName = "episodes")
public class Episode {
    @DatabaseField(id = true)
    private Integer episodeId;

    @DatabaseField(foreign = true)
    private UserShow show;
    ...
}

我正在保存我的 UserShows 对象,例如 in example

UserShow show = new UserShow();
userShowDao.create(show);

for (Episode e: eps) {
    e.setShow(show);
    episodeDao.create(e); 
} 

UserShow 对象有一个外来的惰性集合剧集,但是当我试图获取所有 userShows 时:

shows = userShowsDao().queryForAll();

我正在获取所有带有剧集集合的节目对象。为什么会发生这种情况?集合是懒惰的,我必须得到 null 或其他东西,但没有 Episode 对象的集合。如何让这个集合真的很懒?如果 ORMLite 能够在没有惰性集合的情况下获取对象并在真正需要时进行初始化,那可能会很酷。比如Hibernate.initialize方法。

谢谢!

【问题讨论】:

    标签: android collections ormlite foreign-collection


    【解决方案1】:

    惰性集合已经过很好的测试,并且被许多其他人使用,所以虽然它可能存在错误,但您更有可能被惰性集合类欺骗。

    当从 DAO 检索每个 UserShow 对象时,episodes 将不会为空,而是会使用 LazyForeignCollection 的实例进行设置。但是,不会进行其他查询,并且集合中不会包含 Episode 数据。如果您随后调用集合中的某个方法,例如 userShow.getEpisodes().iterator(),那么此时会进行 单独 查询,以允许您遍历该节目的剧集。这就是惰性集合的工作原理。

    如果您仍然认为惰性集合不起作用,请告诉我们您是如何确定节目有剧集数据的。要查看在哪里进行了哪些查询,您可以启用Android logging with ORMLite


    编辑:

    原来@Georgy 正在使用调试器来调查集合。调试器很可能调用相同的iterator()toArray() 方法,这会导致在该时刻发出集合查询。因此,在调试器请求之前,集合中没有任何剧集。

    【讨论】:

    • 灰色,感谢您的回复。我正在获取带有已初始化剧集集合的 userShows 对象,但是我没有对剧集进行任何调用。
    • 我可以在我的调试器中看到这一点 postimage.org/image/cdqihamc 方法 public List getAllUserShows() { List shows = null;尝试 { 显示 = getHelper().getUserShowsDao().queryForAll(); } catch (SQLException e) { e.printStackTrace(); } 返回节目; }
    • 是的,您的调试器正在调用 iterator() 以及此时进行查询的其他方法。它表明那里有剧集,但在调试器要求它们之前它们不存在。如果您打开日志记录,您应该只能在调试器向您显示有关集合的信息时看到查询被命中。
    • 我相信你,但我想检查并查看正在运行的 sql 查询。你知道如何在 ormlite 或 sqlite 中启用 sql 登录吗?谢谢。
    • 我怀疑你相信我。 :-) 查看在线文档:ormlite.com/docs/android-logging
    【解决方案2】:

    你的例子应该没​​问题。我创建了相关的测试表并插入了 2 个usershows 和 3 个episodes。然后我跟踪 MySQL 日志(通过使用--general-log=&lt;log file name&gt; 运行 MySQL 来设置 - 请参阅http://dev.mysql.com/doc/refman/5.5/en/query-log.html)。

    完整的测试 Groovy 脚本:

    import com.j256.ormlite.dao.DaoManager
    import com.j256.ormlite.jdbc.JdbcConnectionSource
    cs = new JdbcConnectionSource('jdbc:mysql://localhost/episode?user=root')
    epDao = DaoManager.createDao(cs,Episode)
    usDao = DaoManager.createDao(cs,UserShow)
    usDao.queryForAll().each { println it }
    

    日志显示只运行了一条选择语句:

    110830 13:11:09     1 Query SELECT * FROM `usershows`
    

    将最后一行更改为以下内容(遍历所有用户节目并获取每个节目的剧集字段:

    usDao.queryForAll().each { println it.episodes }
    

    结果:

    110830 13:15:31     1 Query SELECT * FROM `usershows`
                        1 Query SELECT * FROM `episodes` WHERE `show_id` = 1
                        1 Query SELECT * FROM `episodes` WHERE `show_id` = 2
    

    【讨论】:

    • 不知道,感谢您的回复。正如我在您的示例中看到的那样,剧集按需获取。但是在我的项目中,当我得到 usetShows 对象并且没有任何对剧集的调用时,无论如何我也会得到剧集。我可以在调试器中看到这一点。如何获得没有剧集的用户节目?
    • 我想调试器会强制检索剧集?也就是说,由于 ForeignCollection 接口是 java.util.Collection 和 Iterable,调试器知道如何查看内容;一旦完成,它就会触发从数据库中检索剧集。
    • 如果这是真的,这是非常奇怪的行为。与休眠行为不同,调试器明确表示收集是惰性的,无法强制执行。
    猜你喜欢
    • 2018-02-27
    • 2014-08-26
    • 1970-01-01
    • 2013-02-27
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    相关资源
    最近更新 更多