Question

I have a case class which has some of its fields as option types. Consider the following case class:

case class TypeA(field1: Int, field2: Option[String], field3: Boolean)

This case class will be instantiated by the persistence layer which calls the database table and returns an instance of this case class. The value for field2 comes from another table in the database and in almost all situations, the method that returns TypeA does not need to set field2. The value for field2 will be set after I return TypeA by doing a database lookup. I want to have field2 in TypeA but I do not want to have that as part of the TypeA constructor. Partial functions, traits come to my mind but since I'm new to Scala, I'm looking for some good practices. Any suggestions?

Was it helpful?

Solution

If I well understand your situation you can do as follows:

case class TypeA(field1: Int, field3: Boolean) {
  lazy val field2 = YourDAO.lookup
}

Note that in this solution field2 is lazily populated and always depends to a database lookup.

OTHER TIPS

Does this accomplish what you want?

case class TypeA(
  field1: Int,
  field2: Option[String] = None,
  field3: Boolean
)

val a = TypeA(field1 = 7, field3 = true)
// a: TypeA = TypeA(7,None,true)

val b = a.copy(field2 = Some("x"))
// b: TypeA = TypeA(7,Some(x),true)

Actually, if you read two table, and then make some aggregated entities from them, I advise you to consider two ways of doing this:

1) Maybe you can make outer join query, that will return you you entities with Option[T] parameter. In our projects we use Squeryl ORM. You can check this: http://squeryl.org/joins.html

   val query = join(typeATable, typeBTable.leftOuter)((a,b) =>
    select((a, b))
    on(a.someField === b.anotherField.?)
   )
   val result: List[(TypeA, Option[TypeB])] = query.toList

Such a query will return List[(TypeA, Option[TypeB])]

Then you can map it to some TypeC you want

2) Another solution: create two DAO services, that will read from database. Then make aggregator service, that will combine results:

TypeA - base trait, that will have different impls

trait TypeA {
  def field1: Int
  def field2: Option[String]
  def field3: Boolean
}

SimpleTypeA - entity that you read from DB. It has field2 as None as you wanted^

case class SimpleTypeA(
  field1: Int,
  field3: Boolean
) extends TypeA {
  val field2: Option[String] = None
}

TypeB - some other type, that you receive from DB:

case class TypeB(...)

And then, AggregatedTypeA - entity, that will have aggregated information from two databases:

case class AggregatedTypeA(
  entity: TypeA,
  anotherEntity: Option[TypeB]
) extends TypeA {
  def field1 = entity.field1 
  //retrive info from anotherEntity: Option[TypeB]
  def field2 = anotherEntity.map(_.someFieldOrMethod)
  def field3 = entity.field3 
}

And then implement services:

select SimpleTypeA from DB

trait TypeADAOService {
   def select(...): List[TypeA] //List[SimpleTypeA]
}

Lookup TypeB in DB

trait TypeBDAOService {
   def lookup(...): Option[TypeB]
}

Aggregate SimpleTypeA and TypeB

trait AggregatedTypeAService {
   def select(...): List[TypeA] //List[AggregatedTypeA]
}

Example impl (with Google Guice)

class AggregatedTypeAServiceImpl @Inject()(
  typeADAOService: TypeADAOService, 
  typeBDAOService: TypeBDAOService
) extends AggregatedTypeAService {
   def select(...) = typeADAOService.select(...).map(simpleA => 
     AggregatedTypeA(simpleA, typeBDAOService.lookup(...)))
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top