Karim Stekelenburg
Karim Stekelenburg

Reputation: 643

How to genericly construct objects from data fetched from database

I have a database with multiple tables and corresponding objects for the table's data. For (almost) all tables I have a Model class, which handle the interaction with it's corresponding table (adding records, fetching data and instantiate an object holding the data.

All Model classes have a getById(int id) method, so I thought it would be nice to put it in a superclass (CoreModel).

But here the thing: Since the Model classes are just a sort of interaction layers, I see no use in creating an instance of it. So I thought I make the class final and it's methods static, but then the problem arises that super() methods cannot be called from static methods.

My question: How is this usually done? I'm sorta new to OOP and am pretty baffled by the whole polymorphism thing. Are there any design patterns or standard solutions to solve this problem in a generic way?

Example code:

public final class CoreModel {

public static ResultSet getById(int id, String table){
    Statement stat = null;
    ResultSet res = null;

    try {
        stat = DatabaseModel.getStatement();
        res = stat.executeQuery("SELECT * FROM `"+table+"` WHERE `id` = " +id);

        res.next();

        stat.close();
        res.close();

    } catch (SQLException ex) {
        // handle any errors
        System.out.println("SQLException: " + ex.getMessage());
        System.out.println("SQLState: " + ex.getSQLState());
        System.out.println("VendorError: " + ex.getErrorCode());
        }
    return res;
    }
}


public final class PersonModel extends CoreModel {

public static Person getById(int id) {
    ResultSet personResult = super.getById(id, "person");
    // instatiate Person object
    return personObj;
    }
}

Upvotes: 1

Views: 604

Answers (2)

Vasu
Vasu

Reputation: 22442

Since the Model classes are just a sort of interaction layers, I see no use in creating an instance of it. So I thought I make the class final and it's methods static, but then the problem arises that super() methods cannot be called from static methods.

First thing is that your CoreModel is final class and you can't extend final classes which you did in your PersonModel and your code will not compile.

Also, it would be good to renameCoreModel as CoreDAO & PersonModel as PersonDAO (which are actually Data Access Objects) because they contain the logic to access database tables/connections/etc. (which is called as DAO layer, look here for this pattern).

In general, Model objects (like Person, Product, etc.. are plain data classes with getters/setters) which are NOT singletons whereas DAO objects (like PersonDAO, CoreDAO, etc..) are singletons.

DAO layer classes need to be singleton (single threadsafe instance for the whole application) which hold only behavior (i.e., contain logic fetching/storing data to/from the database).

Are there any design patterns or standard solutions to solve this problem in a generic way?

In order to avoid the boilerplate code to load the objects (like Person, etc..) from database, you can actually use ORM (Object Relational Mapping) frameworks (implementation of JPA) like Hibernate, spring-data-jpa, etc.. i.e., these frameworks will provide you the API to load/save the objects from/to the persistent store without we directly dealing with lots of PreparedStatement and ResultSet objects.

I suggest you don't need to reinvent/rewriting this boilerplate logic, rather directly use the JPA API. One more point here is that if you use JPA, then you are NOT locked into single ORM vendor, rather you can have the portability to switch across the vendors.

Upvotes: 2

Vahid Hashemi
Vahid Hashemi

Reputation: 5240

What you are asking is called ORM. There are couple of design pattern for creating an ORM you can read about DataMapper or ActiveRecord to understand the concept better.

According to your code get only an Id and generating an object is not enough. you need to have a distinguishable Id so the super class can differ from different object.

One way to create a super class for create different object is Factory design pattern.

Something similar to following code :

//Character Class
public class Character implements Model {
    public String age;
    }
//Person Class
public class Person implements Model {
    public String name;
}
//Model
public interface Model {
}
//CoreModel
public class CoreModel {

    public static <T extends Model> T getById( int id) throws Exception {
        int idType = id % 10; // the id has to be distinguishable
        // get data from DB
        switch (idType) {
            case 0:

                Person person = new Person();
                person.name = "test";
                return (T) Person.class.cast(person);
            case 1:
                Character character = new Character();
                character.age = "100";
                return (T) Character.class.cast(character);
            default:
                throw new Exception("Type Not Found");
        }
    }
}
//Main Class
public class Main {
    public static void main(String[] args) {

        try {
            Person p = CoreModel.getById(100);
            Character c = CoreModel.getById(101);
            System.out.println(p.name);
            System.out.println(c.age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Upvotes: 1

Related Questions