In search of an ORM alternative: Creating a SQL-speaking object

The disadvantages of Object-Relational Mapping (ORM) have already been discussed by a number of developers. The main argument against ORM is that it leads to the creation of DTOs, which encapsulate data, rather than behavior. If one decides to accept this claim, what alternative solutions does he have? One of them is a SQL-Speaking object.

Concrete spalling
Data and logic are inseparable. © Sydney Strata Specialists

Suppose you need to create a XMPP connection for each user in a certain database table without using ORM or DTOs. First, you need to fetch the users from the database table. I am using jcabi-jdbc for database interactions and jooq to create SQL queries. The Connections object is used to cache connections.


public final class Visitors implements Scalar<List<Scalar<XmppConnection>>> {

    private final Connections connections;
    private final Scalar<DataSource> database;
    // Constructor
    public List<Scalar<XmppConnection>> value() throws Exception {
        return new JdbcSession(
            this.database.value()
        ).sql(
            DSL.select(
                DSL.field("user_id"),
            ).from(
                DSL.table("users")
            ).toString()
        ).select(
            new OutcomeListVisitor(
                connections
            )
        );
    }
}

Next, you create a Visitor object for each user. This object creates a XMPP connection using the provided User ID.


public final class OutcomeListVisitor implements Outcome<List<Scalar<XmppConnection>>> {

    private final Connections connections;
    // Constructor
    public List<Scalar<XmppConnection>> handle(
        final ResultSet rset,
        final Statement stmt
    ) throws SQLException {
        final List<Scalar<XmppConnection>> result = new ArrayList<>(
            rset.getFetchSize()
        );
        while (rset.next()) {
            result.add(
                new Visitor(
                    connections,
                    rset.getInt("user_id")
                )
            );
        }
        return result;
    }
}

The Visitor object uses the provided Connections to create a reusable XMPP connection for the user.


public final class Visitor implements Scalar<XmppConnection> {

    private final Connections connections;
    // Constructor
    public XmppConnection value() throws Exception {
        return this.connections.connection(
           this.user
        );
    }
}

Looking over this example, the pervasive usage of ORM becomes questionable. The creation of each abstraction must be guided by the responsibility that can be delegated to it. ORM, on the contrary, pollutes the codebase with numerous dummy data containers, which are managed by a controller. In other words, ORM gives much less than you except from it: Instead of providing entities that can used independently from each other, ORM forces us to split data and behavior by storing data in a DTO and logic in a controller. A SQL-Speaking object, on the other hand, encapsulates data and behavior together, lowering the scope and coupling and increasing coherency.

In essence, I strongly believe that the presence of ORM and DTOs is one of the indicators of a poor architectural design. A sequence of steps required to produce a certain result should be composed of independent and self-sufficient entities. ORM separates each step into components, which lowers coherency as data and the operations with it are split apart.