Project and release info; plus questions, issues and discussions.
Turning data access development into SQL development
No longer bothered by object-relational mismatch
Fronting relational database with document interface
Built-in object-relational data transformation
No more compromise on object model
Providing native support for microservice data patterns
ACID saga, strongly consistent CQRS, and more
Why Data Access Service
Data access Service (DAS) solves the object-relational impedance mismatch (ORIM) problem and speeds up application development.
How?
DAS solves the ORIM problem by:
- Abstracting away the host language from SQL and reducing the data access development to pure SQL development.
- Abstracting away the hard object-relational transformation problem and delegating it to a service engine.
- Automating the tedious data mapping work and making it as simple as clicking a button.
This is in contrast to ORM, which attempts to abstract away SQL from the host language and further complicates the problem.
Learn MoreData access Service (DAS) represents the most flexible and efficient way for relational database access.
How?
DAS defines three types of services:
- The query service is for querying ad hoc DTOs (data transfer objects). It relies on a single well-tuned custom query to fetch the data and a powerful service engine to transform the dataset into an object of the desired shape. It provides developers with the flexibility to design their query model in any way they need.
- The repository service is for CRUD operation of domain objects. On the read side, it is an flexible and efficient query service as the above; on the write side, it batches the DML statements to optimize the database trips.
- The command service is for ad hoc data manipulations in the database. It allows developers to fully leverage the power of DML statements for data manipulation.
This is in contrast to ORM, which often generates N+1 queries for moderately complex objects, even when the eager-loading is enabled. As a result, developers are often forced to compromise on their object models.
A Glimpse of Data Access Service
Query Service
Problem: Imagine that you are given an input as:
{ "city": "Los Angeles" }
You are asked to prepare a query to output a list of customer objects as:
[{ "customerId": 12, "customerName": "John Smith", "addresses": [{ "street": "1638 Grand Ave.", "city": "Los Angeles", "State": "CA" }], "paymentMethods": [{ "methodType": "CREDITCARD", "cardNumber": "26153659890218398", "expireDate": "2025/05" }] }]
or something that is even more complex.
Solution: You could simply
-
Prepare a SQL query as:
SELECT c.customer_id, c.customer_name, a.street, a.city, a.state, pm.method_type, pm.card_number, pm.expire_date FROM customer c LEFT JOIN address a ON a.customer_id = c.customer_id LEFT JOIN payment_method pm ON pm.customer_id = c.customer_id WHERE a.city = :city
-
Click a button to bind the query to the input and output.
A query service is ready for test!
The query service is for retrieving ad hoc DTOs. It always runs a single SQL statement to retrieve the output object(s), as opposed to the N+1 query technique ORM would use, even for very complex output object.
Repository Service
Problem: Imagine that you are given a DDD order aggregate, or something event more complex, as:
{ "orderId": 123, "customer": { "customerId": 12 "customerName": "John Smith" } "items": [{ "itemId":1 "product": { "prodId": 32, "prodName": "Phone", "price": { "currency": "USD", "amount": 999.99, } } }], "totalAmount": 999.99 }
where customer and product are read-only value objects.
You are asked to prepare a repository for the aggregate. The repository shall support read by orderId, read by customerId and read all, depending on whether the query input is:
{ "orderId": 123, }
or
{ "customerId": 345 }
or
{}
Solution: You could simply
-
Prepare a SQL query to read from the order, order_item, customer and product tables, as:
SELECT o.order_id, o.customer_id _c.customer_name, oi.item_id, oi.prod_id _p.prod_name, _p.price_currency, _p.price_amount, sum(_p.price_amount) as total_amount FROM order o JOIN customer _c ON _c.customer_id = o.customer_id LEFT JOIN order_item oi ON oi.order_id = o.order_id LEFT JOIN product _p ON _p.prod_id = oi.prod_id WHERE 1 = 1 AND o.order_id = :order_id AND o.customer = :customer_id
-
Click a button to bind the query to the input and object for read.
-
Click another button to bind the aggregate object to the order and order_item tables for write.
A repository service is ready for test!
The repository service is for CRUD operations of domain objects. On the read side, it is a dynamic query service. On the write side, it supports asymmetric write by design. In this example, it only writes into the order and order_item tables, rather than all the order, order_item, customer and product tables it reads from.
Command Service
Problem: Imagine that you are given an order event as:
{ "eventId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "eventType": "OrderPlaced" "eventTimestamp": "2022-03-06T13:45:30.123" "orderId": 123, "data": "..." }
where data is the event data in the form of a JSON string:
{ "orderId": 123, "customerId": 12 "items": [{ "itemId":1 "prodId": 32, "qty": 100 }] }
to be saved in a JSONB column.
You are asked to prepare a command to save the order event into your PostgreSQL event store and update the order state model in the same ACID transaction.
Solution: You could simply
-
Prepare a sequence of DML statements as:
INSERT INTO event { event_id, event_type, event_timestamp, order_id, data } VALUES ( :eventId, :eventType, :eventTimestamp, :orderId, CAST(:data) ) ; INSERT INTO order ( order_id, customer_id ) SELECT FROM event WHERE event_id = :eventId ; INSERT INTO order_item ( item_id, order_id, prod_id, price, qty ) SELECT FROM event WHERE event_id = :eventId
-
Click a button to bind the SQL statement to the input event record.
A command service is ready for test!
The SQL command service is for ad hoc data manipulation. In this example, it inserts the event record in the event store and then use the INSERT...SELECT statements to create the current order state.
Tools and Servers
All tools and servers are free for your own use
Service Builder
The development tool.
Published to: VSCode Marketplace
License: MIT
Last release: Mar, 2024
Development Server
The development platform.
Published to: AWS Public Gallery
License: BackLogic Free Use
Last release: Mar, 2024
Runtime Server
The production runtime platform.
Published to: AWS Public Gallery
License: BackLogic Free Use
Last release: Dec, 2023
Java Client *
The Java data access client.
Published to: Maven Central
License: Apache 2.0
Last release: Nov, 2023
* For language other than Java, an HTTP client may be used for invoking data access services.
Get Started
Learn more about data access service concepts.
Get started with Service Builder.
Support and Feedback
Your questions and feedbacks are greatly appreciated
GitHub Repositories
service-builder
The development tool. A VS Code extension.
service-builder-pack
VS Code extension pack of Service Builder and aiding tools.
data-access-service-example
An example data access application with example query, command and repository services.
complexity-test
A test data access application to find the boundary of service engine.
java-data-access-client
Java data access client.
jdac-spring-boot-starter
Spring Boot data access client.
jdac-spring-boot-example
Example Spring Boot application with jdac-spring-boot-starter.
web
This site.