Barleydb
An alternative take on Java object relational mapping
Install / Use
/learn @scottysinclair/BarleydbREADME
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
node-connect
342.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
85.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
342.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
342.5kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
