Let's say I have a domain model with no natural id.
class Offer {
ClientId clientId;
CompanyId companyId;
OfferDetails details;
}
Offer is loaded from database by auto-generated key. Then it is modifed e.g. by calling a business method accept, reject or renegotiate. In order to persist the offer I must have this auto-generated key. How should I connect domain entity and id from db? Right now I have an OfferId class with db id and version (I use JPA to persist the aggregate). Is there any better approach?
Right now I have an OfferId class with db id and version
The version shouldn't be part of the ID. The ID needs to be immutable.
There are several strategies to deal with ID generation, but here's the common ones:
Use a GUID which relieves the need to hit a shared data store to generate the ID.
Implement a nextId(): OfferId operation on your repository (implementation could use a DB sequence, etc.):
Offer offer = new Offer(offerRepo.nextId(), ...);
Allow the Offer class to be instantiated without an ID and configure your ORM to generate one. I'm not entirely sure about the JPA spec, but it seems that in Hibernate you can combine #IdClass and #GenerateValue annotations to map a DB-generated identity to a wrapping ID class. Have a look at this test case.
Honestly I dislike delegating the identity assignation/generation to the ORM. If you want to generate the ID from the DB I would suggest the second approach I've described, with a method on the repository (or a dedicated service) that can return the next ID.
Related
I'm exploring ServiceStack and I'm not sure what is the best way to implement some business logic.
Using the "Bookings CRUD" example I would like to enforce the following rule:
a given Booking can only be saved (either created or updated) if the hotel has enough free rooms for the particular dates of that booking
Please note that I'm not asking how to calculate "free rooms".
What I'm asking is, from the architectural point of view, how should this be done.
For example, one way would be:
create a request DTO to query the number of configured rooms (lets call it "QueryRooms")
use the existing "QueryBookings" to query current bookings present in database
create a " : Service" class to customize the Booking Service, in order to intercept the "CreateBooking" and "UpdateBooking" requests
inside the custom methods for "CreateBooking" and "UpdateBooking", somehow get the results of "QueryRooms" and "QueryBookings", check if there are enough free rooms for the current request, and proceed only if so
This doesn't look very clean, because the service "CreateBooking" and "UpdateBooking" would depend of "QueryRooms" and "QueryBookings".
What would be an elegant and effcient solution, using ServiceStatck?
You can override AutoQuery CRUD operations with your own Service implementation using the AutoQuery DTO.
Where you can use the Service Gateway to call existing Services which you can use to perform any additional validation & modify the request DTO before executing the AutoQuery operation to implement the API, e.g:
public class MyCrudServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
public object Post(CreateBooking request)
{
var response = Gateway.Send(new QueryRooms
{
From = request.BookingStartDate,
To = request.BookingEndDate,
});
if (response.Results.Count == 0)
throw new Exception("No rooms available during those dates");
request.RoomNumber = response.Results[0].Id;
return AutoQuery.Create(request, base.Request);
}
}
Note: calling in-process Services with the Service Gateway is efficient as it calls the C# method implementation directly, i.e. without incurring any HTTP overhead.
I am thinking about scenario in a way of Domain Driven design, where I have entity, lets say Cv (Curriculum vitae), which state is saved in database via repository.
Now I need to store part of the Cv in another system (ElasticSearch), which is crucial for whole app functionality like searching.
How to handle it? I am thinking about these 2 options:
1. Use domain service IndexCvGatewayServiceInterface (as interfaces implemented in infrastructure)
class CvEntity
{
public function approve(CvRepositoryInterface $cvRepository, IndexCvGatewayServiceInterface $indexService)
{
$cvRepository->update($this);
$indexService->update($this);
}
}
2. Listen to domain event (create infrastructure listener)
class CvEntity
{
public function approve(CvRepositoryInterface $cvRepository, EventDispatcheInterface $dispatcher)
{
$cvRepository->update($this);
$dispatcher->dispatch(new CvApprovedEvent($this));
}
}
I like option 2. because it separates logic for non state change purposes into infrastructure, but there is also concern, that we should know about searching as important part of our app.
You're facing here Write and Read model. Ideally after persist your entity/aggregate in the write model you should dispatch the uncommitted events of this entity and listing/subscribe to them to generate the projections (partials in elastic in your use case). For reference: https://github.com/jorge07/symfony-5-es-cqrs-boilerplate/blob/symfony-5/src/Infrastructure/User/ReadModel/Projections/UserProjectionFactory.php#L17
IMO, Entity should not contain the repository.
I'm curious why the decision was made to couple the Service base class in ServiceStack to data access (via the Db property)? With web services it is very popular to use a Data Repository pattern to fetch the raw data from the database. These data repositories can be used by many services without having to call a service class.
For example, let's say I am supporting a large retail chain that operates across the nation. There are a number of settings that will differ across all stores like tax rates. Each call to one of the web services will need these settings for domain logic. In a repository pattern I would simply create a data access class whose sole responsibility is to return these settings. However in ServiceStack I am exposing these settings as a Service (which it needs to be as well). In my service call the first thing I end up doing is newing up the Setting service and using it inside my other service. Is this the intention? Since the services return an object I have to cast the result to the typed service result.
ServiceStack convenience ADO.NET IDbConnection Db property allows you to quickly create Database driven services (i.e. the most popular kind) without the overhead and boilerplate of creating a repository if preferred. As ServiceStack Services are already testable and the DTO pattern provides a clean endpoint agnostic Web Service interface, there's often not a lot of value in wrapping and proxying "one-off" data-access into a separate repository.
But at the same time there's nothing forcing you to use the base.Db property, (which has no effect if unused). The Unit Testing Example on the wiki shows an example of using either base.Db or Repository pattern:
public class SimpleService : Service
{
public IRockstarRepository RockstarRepository { get; set; }
public List<Rockstar> Get(FindRockstars request)
{
return request.Aged.HasValue
? Db.Select<Rockstar>(q => q.Age == request.Aged.Value)
: Db.Select<Rockstar>();
}
public RockstarStatus Get(GetStatus request)
{
var rockstar = RockstarRepository.GetByLastName(request.LastName);
if (rockstar == null)
throw HttpError.NotFound("'{0}' is no Rockstar".Fmt(request.LastName));
var status = new RockstarStatus
{
Alive = RockstarRepository.IsAlive(request.LastName)
}.PopulateWith(rockstar); //Populates with matching fields
return status;
}
}
Note: Returning an object or a strong-typed DTO response like RockstarStatus have the same effect in ServiceStack, so if preferred you can return a strong typed response and avoid any casting.
I've written a Jersey-client application that interacts with two web services, one that is REST, the other that is SOAP. I use the employee data supplied by the REST service to create an new User with the SOAP service.
The REST service is a JAX-RS (Jersey) application that returns an Employee entity:
#Entity
#Table(name = "EMPLOYEE_TABLE")
#XmlRootElement
public class Employee implements Serializable {
...
}
I have not explicitly created a schema definition for the entity class.
A GET request returns a representation of the Employee entity:
GET /employees/100
<Employee id='100' providerId='3345'>
<Link type="application/xml" href="/employees/100" rel="self"/>
<Name>Doe, Dr. John</Name>
<Departments>
<Department id='10'><Name>Emergency Medicine</Name></Department>
<Department id='56'><Name>Behavioral Medicine</Name></Department>
</Departments>
</Employee>
The SOAP service (BusinessObjects Enterprise web-services SDK) provides a Java client to simplify its usage.
While I could parse the XML-representation of the Employee entity and assign it to the appropriate setters of the User class, it would probably be easier to create an Employee proxy class (with the appropriate annotations) in my Jersey client application.
Questions:
Does JAX-RS (specifically Jersey, in my case) have a mechanism to expose an entity's schema definition (XSD format)? The WADL document doesn't include this type of information.
While I could manually create a POJO-class representation that mimics the Employee resource class, I should probably be using a 'tool'. What are my options for this?
As time progresses, I may need to add additional elements to the Employee entity. Does this mean that a new version of the RESTful services needs to be created?
Assuming that Jersey can be configured to automatically generate and expose a schema definition, and that changes to the Employee would then alter the schema definition, should the Employee entity implement an interface to prevent unauthorized changes?
Concerning question 1, if your XSD is deployed in your webapp you can just navigate to it in a browser. For example, in my webapp I have an /xsd folder containing my XSD. When the app is running I can point my browser to http://localhost:8080/<app_name>/xsd/<xsd_name>.xsd and see the XSD.
I'm still learning about DDD and I have these two (probably simple) questions:
If a Factory creates new object/graph/aggregate instances, but also "reconstitutes" objects/graphs from the Repository, then:
(1) Does your service layer functions/jobs/tasks/unit-of-work call into the Factory or a behavioural method on the Entity instance or a DomainService function? I'm lost as to the call stack based on the responsibility of these components.
(2) Do Entity instances even have "behavioural methods" like above? For example does a Post have p.UpdatePost(string bodyText) or is that not a concern of the domain model and so the same should be achieved with the Repository? Or the service layer function, should it be calling the Repository in this case and the entity instance simply have behavioural methods that are specific to the domain and not persistence? But then, why does it sound like "updating a post" is a domain function when that's the user's goal?
You can see I'm all over the place. Please help.
(1) Does your service layer functions/jobs/tasks/unit-of-work call into the Factory or a behavioral method on the Entity instance or a DomainService function? I'm lost as to the call stack based on the responsibility of these components.
Usually - top level retrieves necessary aggregate root and calls a function on it. Sometimes top level retrieves multiple aggregate roots and pass them to domain service, but not often because domain service is a quite strong sign that there is unrecognized aggregate root. At the end - top level ensures aggregate root is persisted.
(2) Do Entity instances even have "behavioural methods" like above? For example does a Post have p.UpdatePost(string bodyText) or is that not a concern of the domain model and so the same should be achieved with the Repository? Or the service layer function, should it be calling the Repository in this case and the entity instance simply have behavioural methods that are specific to the domain and not persistence? But then, why does it sound like "updating a post" is a domain function when that's the user's goal?
Yes, they do. Domain model should be aware of it's state changes. And that's much more beneficial as it seems at first. Great thing about this is that You gain extensibility point. If client will walk week later to You and say that he wants system to check additional things when user updates post - instead of searching every line of post.bodyText="new value", You will be able to go straight to post.UpdatePost method and attach necessary things there.
On the other hand - CRUD is not mutually exclusive with domain driven design. E.g. - in my application, management of users and their roles is uninteresting enough that I'm not even trying to model it granularly. You need to recognize parts what matters in business Your application is describing and working with.
Keep in mind that domain driven design makes sense for complex applications only. Simple blog application doesn't need it.
(3) Am I wrong in assuming that a service layer (not Domain Services) should encapsulate how an interface interacts with the Domain Layer?
As I see it - application services are more for orchestrating infrastructure. If there is no infrastructure involved - then application service loses value:
Application services basically are just facades. And every facade is bad if complexity it adds overweights problems it solves.
Inside domain:
//aggregate root is persistence ignorant.
//it shouldn't reference repository directly
public class Customer{
public string Name {get; private set;}
public static Customer Register(string name){
return new Customer(name);
}
protected Customer(string name){
//here it's aware of state changes.
//aggregate root changes it's own state
//instead of having state changed from outside
//through public properties
this.Name=name;
}
}
//domain model contains abstraction of persistence
public interface ICustomerRepository{
void Save(Customer customer);
}
Outside of domain:
public class CustomerRepository:ICustomerRepository{
//here we actually save state of customer into database/cloud/xml/whatever
public void Save(Customer customer){
//note that we do not change state of customer, we just persist it here
_voodoo.StoreItSomehow(customer);
}
}
//asp.net mvc controller
public class CustomerController{
public CustomerController(ICustomerRepository repository){
if (repository==null)throw new ArgumentNullException();
_repository=repository;
}
public ActionResult Register(string name){
var customer=Customer.Register(name);
_repository.Save(customer);
}
}