findById with #includes doesn't return a result as expected when assocations are absent
yamitzky opened this issue · comments
I found a weird behavior about ORM's eager loading (not sure if it is a "bug")
I define a model like;
case class Article(
id: Int,
title: String,
body: String,
createdAt: DateTime,
userId: Int,
user: Option[User] = None
)
object Article extends SkinnyCRUDMapperWithId[Int, Article] {
override lazy val tableName = "articles"
override lazy val defaultAlias = createAlias("a")
override def idToRawValue(id: Int): Any = id
override def rawValueToId(value: Any): Int = value.toString.toInt
override def extract(rs: WrappedResultSet, rn: ResultName[Article]): Article = {
autoConstruct(rs, rn, "user")
}
lazy val userOpt = {
belongsTo[User](
right = User,
merge = (a, u) => a.copy(user = u)
).includes[User](
merge = (as, us) => as map { a =>
us.find(u => a.user.exists(_.id == u.id))
.map(u => a.copy(user = Some(u)))
.getOrElse(a)
})
}
}
Then, find articles like;
Article.includes(Article.userOpt).findById(article_id) // type is Option[Article]
// notice that findAll().headOption returns same result
When user is found, article is not empty. But when user is not found, article is empty!
On the other hand, I tried a case not using eager loading, and found different behavior.
object Article extends SkinnyCRUDMapperWithId[Int, Article] {
/* skip */
belongsTo[User](
right = User,
merge = (a, u) => a.copy(user = u)
).includes[User](
merge = (as, us) => as map { a =>
us.find(u => a.user.exists(_.id == u.id))
.map(u => a.copy(user = Some(u)))
.getOrElse(a)
}).byDefault
}
Article.findById(article_id) returns
In this case, article is not empty whether user is empty or not, and I think this is more natural behavior.
So, the question is that, is this an expected specification and can I avoid the default eager loading's behavior(wanna always get non-empty result)?
Environment:
- Skinny ORM w/ Play framework
- version: 1.3.8
- repository: https://github.com/yamitzky/nonplay-play
- SQL is below(and it returns some rows)
select a.id as i_on_a, a.title as t_on_a, a.body as b_on_a, a.created_at as ca_on_a, a.user_id as ui_on_a , u.id as i_on_u, u.name as n_on_u, u.gender as g_on_u, u.attr1 as a1_on_u, u.attr2 as a2_on_u, u.attr3 as a3_on_u, u.attr4 as a4_on_u, u.attr5 as a5_on_u, u.attr6 as a6_on_u, u.attr7 as a7_on_u, u.attr8 as a8_on_u, u.attr9 as a9_on_u, u.attr10 as a10_on_u, u.attr11 as a11_on_u, u.attr12 as a12_on_u, u.attr13 as a13_on_u, u.attr14 as a14_on_u, u.attr15 as a15_on_u, u.attr16 as a16_on_u, u.attr17 as a17_on_u, u.attr18 as a18_on_u, u.attr19 as a19_on_u, u.attr20 as a20_on_u, u.attr21 as a21_on_u, u.attr22 as a22_on_u, u.attr23 as a23_on_u from articles a left join users u on a.user_id = u.id where a.id = 1;
This seems to be a bug. I just took a look at this issue and figured out the reason(my silly mistake).
I'll fix this issue later and release 1.3.9 as soon as possible.
As far as this case, using #joins instead will work as expected (right, I guess you're just evaluating skinny's eager loading feature).
Thank you for your report!
Thank you for the answer, and I am loooooking forward the fix!