XUtils

hibernated

HibernateD is an ORM for D (similar to [Hibernate](https://hibernate.org/)).


Sample code:

import hibernated.core;
import std.algorithm;


// Annotations of entity classes

class User {
    long id;
    string name;
    Customer customer;
    @ManyToMany // cannot be inferred, requires annotation
        LazyCollection!Role roles;
}

class Customer {
    int id;
    string name;
    // Embedded is inferred from type of Address
    Address address;

    Lazy!AccountType accountType; // ManyToOne inferred

    User[] users; // OneToMany inferred

    this() {
        address = new Address();
    }
}

@Embeddable
class Address {
    string zip;
    string city;
    string streetAddress;
}

class AccountType {
    int id;
    string name;
}

class Role {
    int id;
    string name;
    @ManyToMany // w/o this annotation will be OneToMany by convention
        LazyCollection!User users;
}

int main() {

    // create metadata from annotations
    EntityMetaData schema = new SchemaInfoImpl!(User, Customer, AccountType, 
            Address, Role);




    // setup DB connection factory
    version (USE_MYSQL) {
        import ddbc.drivers.mysqlddbc;
        MySQLDriver driver = new MySQLDriver();
        string url = MySQLDriver.generateUrl("localhost", 3306, "test_db");
        string[string] params = MySQLDriver.setUserAndPassword("testuser", "testpasswd");
        Dialect dialect = new MySQLDialect();
    } else {
        import ddbc.drivers.sqliteddbc;
        SQLITEDriver driver = new SQLITEDriver();
        string url = "zzz.db"; // file with DB
        static import std.file;
        if (std.file.exists(url))
            std.file.remove(url); // remove old DB file
        string[string] params;
        Dialect dialect = new SQLiteDialect();
    }
    DataSource ds = new ConnectionPoolDataSourceImpl(driver, url, params);


    // create session factory
    SessionFactory factory = new SessionFactoryImpl(schema, dialect, ds);
    scope(exit) factory.close();

    // Create schema if necessary
    {
        // get connection
        Connection conn = ds.getConnection();
        scope(exit) conn.close();
        // create tables if not exist
        factory.getDBMetaData().updateDBSchema(conn, false, true);
    }

    // Now you can use HibernateD

    // create session
    Session sess = factory.openSession();
    scope(exit) sess.close();

    // use session to access DB

    // read all users using query
    Query q = sess.createQuery("FROM User ORDER BY name");
    User[] list = q.list!User();

    // create sample data
    Role r10 = new Role();
    r10.name = "role10";
    Role r11 = new Role();
    r11.name = "role11";
    Customer c10 = new Customer();
    c10.name = "Customer 10";
    c10.address = new Address();
    c10.address.zip = "12345";
    c10.address.city = "New York";
    c10.address.streetAddress = "Baker st., 12";
    User u10 = new User();
    u10.name = "Alex";
    u10.customer = c10;
    u10.roles = [r10, r11];
    sess.save(r10);
    sess.save(r11);
    sess.save(c10);
    sess.save(u10);

    // load and check data
    User u11 = sess.createQuery("FROM User WHERE name=:Name").
        setParameter("Name", "Alex").uniqueResult!User();
    assert(u11.roles.length == 2);
    assert(u11.roles[0].name == "role10" || u11.roles.get()[0].name == "role11");
    assert(u11.roles[1].name == "role10" || u11.roles.get()[1].name == "role11");
    assert(u11.customer.name == "Customer 10");
    assert(u11.customer.users.length == 1);
    assert(u11.customer.users[0] == u10);
    assert(u11.roles[0].users.length == 1);
    assert(u11.roles[0].users[0] == u10);

    // remove reference
    u11.roles = u11.roles().remove(0);
    sess.update(u11);

    // remove entity
    sess.remove(u11);
    return 0;
}

Additional Features

Composite Keys

If a database contains tables with a composite primary key, the @EmbeddedId can be used to represent this. The columns that represent the primary key should be in an @Embeddable class which is then referenced in a property annotated with @EmbeddedId.

For example, consider a database table created via the following SQL command:

CREATE TABLE invoices (
    vendor_no VARCHAR(8) NOT NULL,
    invoice_no VARCHAR(20) NOT NULL,
    amount_e4 INTEGER);
ALTER TABLE invoices
    ADD CONSTRAINT invoices_pkey PRIMARY KEY (vendor_no, invoice_no);

To represent this using HibernateD, the following code would be used:

@Embeddable
class InvoiceId {
    string vendorNo;
    string invoiceNo;

    // Be sure to implement this to benefit from session caching.
    bool opEquals(const InvoiceId o) const @safe {
        return vendorNo == o.vendorNo && invoiceNo == o.invoiceNo;
    }
}

@Table("invoices")
class Invoice {
    @EmbeddedId InvoiceId invoiceId;
    int amountE4;
}

Note: At the time of writing, there are important limitations.

  1. The function DBInfo.updateDbSchema(Connection conn, bool dropTables, bool createTables) does not generate schemas with compound keys.
  2. The Hibernate annotation @JoinColumns (plural) has not yet been implemented, thus, the @ManyToOne and @ManyToMany relations are not usable for classes using an @EmbeddedId.
  3. The @Embedded class referenced via an @EmbeddedId property should implement opEquals in order to gain performance benefits from session caching. These features will be added in future updates.

Articles

  • coming soon...