SkillAgentSearch skills...

Barleydb

An alternative take on Java object relational mapping

Install / Use

/learn @scottysinclair/Barleydb
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

BarleyDB

BarleyDB is a Java ORM library which makes it as easy as possible to load and save application domain models to and from the database. It is also extremely powerfull with a lot of features.

Query model generation

Query DSL classes are auto-generated from a schema specification and allow the programmer to easily build queries to load their application data.

  QUser quser = new QUser();
  quser.joinToAddress();
  QDepartment qdepartment = quser.joinToDepartment();
  qdepartment.joinToCountry();
  
  List<User> users = ctx.performQuery( quser ).getList();

Domain model generation

Application domain models are autogenerated from a schema specification.

Domain model inheritence

The object orientated inheritence model is supported, where entities can extend other entities. The generated domain model classes extend each other as required by the Java programming language and abstract query DSL classes are also generated allowing abstract data to be queried.

//load all people 
for (Person person: ctx.performQuery(new QPerson()).getList()) {
  if (person instanceof Employee) {
    Employee emp = (Employee)person;
    ...
  }
  else if (person instanceof Customer) {
    Customer cust = (Customer)person;
    ...
  }
}

Complex where clauses

The Query DSL support the usual operators logical and arithmetic operators as well as subqueries for example.

  QUser quser = new QUser();
  QDepartment qdepartment = quser.existsDepartment();
  quser.where( quser.name().equal("fred") )
       .andExists( qdepartment.where( qdepartment.name().like("computing") ) );

Batching multiple queries

The queries will be combined into a composite query returning multiple result-sets (depending on database vendor support).

QueryBatcher batch = new QueryBatcher();
batch.addQuery(new QUser());
batch.addQuery(new QDepartment());
batch.addQuery(new QCountry());

ctx.performQueries( batch );

Fetch plan definition whenever you want

Fetch plans for lazy loading can be registered at any time by specifying query models with the desired joins.

//create and register the fetch plan to be used the next time a deparment must be fetched.
QDepartment qdepartment = new QDepartment();
qdepartment.joinToCountry();
ctx.registerQuery( qdepartment );

//call user.getDepartment() which will cause a fetch.
Department dep = user.getDepartment();
//country was fetch along with the deparment as per the fetch plam
Country country = dep.getCountry();

Persisting changes to the database

Persist requests are used to bundle together domain models to be persisted. Persist operations cascade down to owned relations as expected.

PersistRequest pr = new PersistRequest();
pr.save( userA, userB, userC );
pr.delete( userX, userY );

ctx.persist( pr  );

Dependency analysis and batching of operations

During persistence, a dependency tree is used to identify the correct operation order to satify database constraints and to promote operation batching.

BatchExecuter executing insert batch for EntityType [ org.example.acl.model.AccessArea ] of size 1
BatchExecuter 1 rows were modified in total
BatchExecuter executing insert batch for EntityType [ org.example.etl.model.Template ] of size 1
BatchExecuter 1 rows were modified in total
BatchExecuter executing insert batch for EntityType [ org.example.etl.model.TemplateContent ] of size 2
BatchExecuter 2 rows were modified in total
BatchExecuter executing insert batch for EntityType [ org.example.etl.model.BusinessType ] of size 2
BatchExecuter 2 rows were modified in total
BatchExecuter executing insert batch for EntityType [ org.example.etl.model.TemplateBusinessType ] of size 2
BatchExecuter 2 rows were modified in total

DTO Models

DTO classes are automatically generated which allow programmers to work with simple DTO objects. DTOConverter utilities are provided to make it very easy to convert between DTOS and Entities

public List<UserDto> loadUsers() {
 //create a ctx and perform the  query
 EntityContext ctx = new EntityContext(env, namespace);
 List<User> users = ctx.performQuery(new QUsers()).getList(); 

 //convert all entities in the ctx to dtos
 DtoConverter converter = new DtoConverter(ctx);
 converter.convertToDtos();

 //get the list of userDtos which match the list of user entities from the query.
 List<UserDto> usersDto = converter.getDtos(users);
 return usersDto;
}

The DTOs extend BaseDto and have both EntityState and EntityConstraints so that information is not lost when mapping to and from entities. 1:N relationships are managed with DtoList which keeps track of the fetched state of the 1:N relation.

// update account 100
 AccountDto account = new Account();
 account.setId(100);
 //set the fetched state to true - indicates that the relation is considered fetched and therefore already contains all data
 account.getTransactions().setFetched(true);
 account.getTransactions().add( tran1 );
 account.getTransactions().add( tran2 );
 
 service.save(account);

Auditing

Auditing is very straightforward as a change report is generated every time domain models are persisted. The report below shows the table name, column name, old value and new value.

audit AUDIT SS_XML_MAPPING                 ID                             null                           3                             
audit AUDIT SS_XML_MAPPING                 SYNTAX_MODEL_ID                null                           1                             
audit AUDIT SS_XML_MAPPING                 XPATH                          null                           /root3                        
audit AUDIT SS_XML_MAPPING                 TARGET_FIELD_NAME              null                           target3                       
audit AUDIT SS_XML_MAPPING                 ID                             null                           4                             
audit AUDIT SS_XML_MAPPING                 SYNTAX_MODEL_ID                null                           2                             
audit AUDIT SS_XML_MAPPING                 XPATH                          null                           sub1                          
audit AUDIT SS_XML_MAPPING                 TARGET_FIELD_NAME              null                           subtarget1                    
audit AUDIT SS_XML_MAPPING                 ID                             null                           5                             
audit AUDIT SS_XML_MAPPING                 SYNTAX_MODEL_ID                null                           2                             
audit AUDIT SS_XML_MAPPING                 XPATH                          null                           sub2                          
audit AUDIT SS_XML_MAPPING                 TARGET_FIELD_NAME              null                           subtarget2     

Access control

An access control check is performed on each and every update insert or delete operation. A 3rd party access control library can easily be plugged in to the framework.

Relationship management

Ownership vs simple referral relationships impact how data is persisted across relations.

  • Ownership causes inserts, updates and orphan removal to be performed.
  • Simple refferal causes inserts to be performed when the referred to entity is new.

Freshness checking (optimistic locking)

BarleyDB will verify any optimistic locks defined on entities.

  • Relationship management works in combination with optimistic locking, so that owned data can cause the owner's optimistic lock to be updated.
  • The dependsOn relationship requires that the entity depended on must also be fresh, even if it is not being saved.

Transaction management

ctx.setAutocommit(false);
..
..
ctx.commit();

Large data-set support / streaming

Domain models can be streamed from the database.

QUser quser = new QUser();
quser.joinToAddress();

try ( ObjectInputStream<User> in = ctx.streamObjectQuery( quser ); ) {
  User user;
  while( (user = in.read()) != null ) {
    ...
  }
}

A stream can also be opened on any 1:N relation on any domain model.

try ( ObjectInputStream<Address> in = user.streamAddresses(); ) {
  Address address;
  while( (address = in.read()) != null ) {
    ...
  }
}

Garbage collection of unreferenced entities

BarleyDB supports garabage collection so that entities which are no longer referred to are removed. This works very well in combination with large data-set streaming as memory will be reclaimed automatically as the program proceeds through the data stream.

3 tier architecture support

BarleyDB can be used on the client tier in a 3 tier architecture. A client can create a remote context to the application server to perform queries and persist domain models as normal.

Easy domain schema specification

Both Java and XML Schema definition is supported though Java is preferred as the compiler can catch any inconsistencies.

public class ApplicationSpec extends PlatformSpec {

    public ApplicationSpec() {
        super("com.mycomp.application");
    }

    @Enumeration(JdbcType.INT)
    public static class EmployeeType {
        public static final int ADMIN = 1;
        public static final int ENGINEER = 2;
        public static final int MANAGER = 3;
        public static final int HR = 4;
        public static final int CHIEF = 5;
    }

    @Enumeration(JdbcType.INT)
    public static class Language {
        public static final int ENGLISH = 1;
        public static final int FRENCH = 2;
        public static final int SPA

Related Skills

View on GitHub
GitHub Stars51
CategoryDevelopment
Updated1y ago
Forks5

Languages

Java

Security Score

80/100

Audited on Jun 16, 2024

No findings