This one had me digging in the squeryl and record source all day
yesterday. If you retrieve an entity and then try to use one of it's
fields in a subsequent query the code will compile but you'll get a
NoSuchElementException when you try to execute it. So something like:
val theOne = from(one)(o => where (o.idField === "one") select
(o)).head
val theMany = from(many)(m => where (m.oneId === theOne.idField)
select(m))
Will fail. The reason is that Squeryl instruments the parameters used
within a from statement and sets
FieldReferenceLinker._lastAccessedFieldReference when a Field var is
accessed on an instrumented object. Since theOne isn't passed into
the from it isn't instrumented,
FieldReferenceLinker._lastAccessedFieldReference is empty and code
like this in RecordTypeMode will result in the exception:
implicit def long2ScalarLong(l: MandatoryTypedField[Long]) =
new SelectElementReference[LongType]
(FieldReferenceLinker.takeLastAccessedFieldReference.get)
(createOutMapperLongType) with NumericalExpression[Long]
Notice the .get call on
FieldReferenceLinker.takeLastAccessedFieldReference which returns and
Option. Yes, using val theMany = from(many)(m => where (m.oneId ===
theOne.idField.is) select(m)) will work but it doesn't seem intuitive
to me at all that direct references to columns are ok in some
situations and not ok in others, especially when the implicit
conversion happens and the code doesn't fail until runtime. After
looking at the Squeryl code I saw that typically a
ConstantExpressionNode is created in situations where
FieldReferenceLinker._lastAccessedFieldReference is not available and
when I changed the above to:
implicit def long2ScalarLong(l: MandatoryTypedField[Long]):
NumericalExpression[LongType] =
FieldReferenceLinker.takeLastAccessedFieldReference match {
case Some(n: SelectElement) => new SelectElementReference[LongType]
(n)(createOutMapperLongType) with NumericalExpression[LongType]
case None => new ConstantExpressionNode[LongType](
l.is) with
NumericalExpression[LongType]
}
It seemed to fix the problem. Is there a reason this isn't the way
that RecordTypeMode works now? I've changed all the
MandatoryTypedField implicits to this form and didn't notice any
issues in the testing that I did. If we can agree that this is a
change that should be made I'd be willing to update the
OptionalTypedFields as well and contribute the changes back.
-Dave