5

My application's model includes a number of entities that share many common properties, and are operated on by many of the same classes.

If I was using an ORM, I'd define an abstract class with the common properties, setup class table inheritance for persistence, and have the classes that operate on all these entity types operate on the abstract class.

However, I am using Slick, not an ORM. I could easily jury-rig an ORM-like solution:

sealed trait Shape {
   def id: Long
   def color: String
}  

case class Triangle(id: Long, color: String, a: Int, b: Int, c: Int)  extends Shape
case class Square(id: Long, color: String, sideLength: Int) extends Shape

//Hides the fact that shape instances are persisted in two tables
class ShapeDAO {
  def create(shape: Shape) : Unit 
  def update(shape: Shape) : Unit
  def retrieve(id: Long): Option[Shape]
  def delete(id: Long): Unit
}

I lose the composability that's such a big selling point for slick, but it seems like I might be able to get that back by adding something heinous like this:

def rawShape: Query = 
   (shapes joinLeft triangles on (shapes.id === triangles.id) 
           joinLeft squares on (shapes.id === squares.id)) map {
        shape_type match {
            case "triangle" => Triangle(shape, triangle)
            case "square" => Square(shape, square) 
    }

I could then join off of rawShape or otherwise use it in cases where I need more flexibility.

How bad is what I'm suggesting? Complicated queries that might benefit from being able to build off of something like rawQuery are very rare in this application... for the most part we're just CRUD-ing single entities in very simple ways. Having a common base class and a single DAO that encapsulates all the messy details of getting shapes would be a big win for the project, in that it would keep classes that have to deal with shapes simple.

1 Answer 1

1

I have found inheritance to be an anti-pattern for relational databases. Instead, concrete types can be defined, then aggregated with UNION views. Each type should have a separate table. If you want them to share an identity sequence, you can do that with PostgreSQL (and likely others).

If you ever want to query all "Shapes", then you can have a separate type definition for that which maps to an SQL view that UNIONs triangle and square.

A CRUD data access layer is also mostly an anti-pattern. Your ShapeDAO class is a bit of a repository pattern. It's one that hides (disables?) the capabilities of your ORM, Slick.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.