According to the migration of SDN (Spring-data-neo4j) v3 to SDN4, Indexes are not present anymore, so this is not foreseen to work anymore.
#NodeEntity
public class User extends Unversioned{
#Indexed(unique=true,failOnDuplicate = true) // <-- THIS
private String login;
...
}
According to here or there, no-one seems surprised. Isn't that the "point" to have constraints defined on the model itself ?
The mission defined on the main page of Sring-data:
Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store.
Even when comparing to the latest Spring-data-JPA official example, constraints are still defined on the model:
#Entity
public class Customer extends AbstractEntity {
private String firstname, lastname;
#Column(unique = true)
private EmailAddress emailAddress;
Allowing constraints to be defined on the very java-based-model seemed to me to be the less error-prone system.
How are we supposed to build a model consistent if the model & constraints are decoupled ? What am I missing ?
I will try to give you an answer "from the trenches". I used SDN 3.x quite a lot, now I use 4.x, I also use spring data mongo, which has #Indexed annotation.
I agree it is very convenient when you just want to create an index on a property.
But there are several problems in the long run. When the application is deployed and maintained I had to resort to managing indexes in code, not declaratively.
These include
renaming the property, won't delete the old index
changing the index (e.g. making it unique constraint)
these annotation usually don't provide all the possibilities of the native database index definition
class hierarchies - what if you have an #Indexed on a property in a base class - what index(es) are created? Just for the base class label? (or collection in mongo), all children...?
In the end you trade one line with #Indexed annotation for another
#Autowired
private Neo4jOperations operations;
#PostConstruct
public void createIndexesAndConstraints() {
...
operations.query("CREATE INDEX ON :Person(email)", EMPTY_MAP);
...
}
As of SDN 4, index management is considered to be out of scope for the mapping framework, and it is recommended that they be managed outside of Spring.
More info: http://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#reference_programming-model_indexing
Related
DDD says that you domain models needs to be expressive and say what they need. With that in mind I created the following class:
#Entity
public class User{
#Id
#GeneratedValue
private Long id;
private String userName;
private String password;
public User(String userName, String password) {
/**set the values*/
}
/** Validations, getters and business methods*/
With this constructor I tell that the minimun needed to build a new User object.
The problem with that approach is that JPA needs a non-argument default constructor to instatiate the class by reflections. In this case do I have to forget about that DDD sugestion or is there a workaround?
In your specific situation you can make the non-argument constructor private. But soon another JPA requirement will force you to make another workaround;
voiceofunreason gave you the right answer. The right way is to have an adapter in the infrastructure/persistence layer that receives your domain object and then convert it to a JPA anemic model and vice versa.
Some other options that fits better without too much conversions:
1 - Spring Data JDBC is trying to absorb Aggregates concept
https://www.youtube.com/watch?v=GOSW911Ox6s&t=3s;
https://docs.spring.io/spring-data/jdbc/docs/1.1.7.RELEASE/reference/html/#reference
2 - Persist your aggregate as a json in a relational database. Vaughn Vernon proposed an implementation -> https://kalele.io/the-ideal-domain-driven-design-aggregate-store/
3 - Document oriented database such as https://www.mongodb.com/ among others...
In this case do I have to forget about that DDD sugestion or is there a workaround?
There isn't really a good answer here. There's a tension at work when we try to mix objects with mutable, encapsulated state, and persistence (ie: storing the authoritative copy of state in some anemic durable store).
The "right" answer is that we don't use an O/RM to load domain entities from the durable store; the O/RM loads a DTO, and we copy information from the DTO into the domain object. Similarly, to save, you extract information from the domain entity and copy it into the DTO, then save the DTO.
In other words, the O/RM loads an in memory representation of an anemic data structure.
In practice, it's a lot more common to couple the entity state to the O/RM, implementing within the domain entity whatever interfaces the O/RM needs to do its work.
The trick is to make sure that you can decouple your implementation from the O/RM when the O/RM assumptions start to get in the way. For instance, you should be able to easily change a specific aggregate from using a relational data store to using a document data store without requiring a rewrite of your entire system.
I am currently trying to implement R2DBC within Spring Boot for an application that is already far into development - meaning, unfortunately, our DDL is not flexible, since other microservices depend on this it and vice versa. One significant limitation of R2DBC is that is does not support nested classes. Moreover, it does not support JPA, since that would would defeat the purpose of being all-around non-blocking. So all those useful annotations are off the table as well.
The class I am dealing with looks something like this:
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Stats {
#Id
StatsPK statsPK
#Column(stat_name)
String stat;
...
#Data
#AllArgsConstructor
#NoArgsConstructor
#Embeddable
public static class StatsPK implements Serializable {
#Column("store_id")
private Integer storeId;
#Column("empl_id")
private String emplId;
#Column("app_version")
private String appVersion;
}
}
After researching my question, I have found many ways to go about accounting for the composite key, including what is already been shown in the example above (using the #Embeddable annotation), using a custom PK object (which is similar, but would have the option of using a class designed for this purpse, such as CompositeKeyHolder), The JPA #TableId(TableId.class) annotation, and some others that seemed less promising.
All of these options seem to either be utilizing JPA or utilizing a nested object, which I cannot do. I can't really think of a way to get around these limitations. But since I'm a beginner, I decided to ask in case anyone has dealt with this issue before.
Appreciate any feedback.
Spring Data R2DBCs repository abstraction does not support composite keys yet.
What you could use the DatabaseClient though to construct your SQL and to query data.
It seems to me that almost by default all code first POCO's should have private setters for their primary key a.k.a. auto-generated Id.
Like this -
public int id { get; private set; }
Is this an incorrect assumption? I do not want my API to allow setting of an auto-generated column.
Exposing a public setter should not be an issue since it is unadvised to even expose this POCO outside the Data Access Object layer..
Exposing a POCO decorated with a specific framework's attributes, or even a POCO which discloses some kind of information regarding storage (Entity Relational Database, in this instance) is a bad practice.
Consider wrapping it in an interface and returning it as an instance of that interface. This way you get to enjoy the best of both worlds. Exposing the properties which are necessary and allowing to set only a part of them.
In any case, I do not think that EF will like the private setter thing too much.
Hy,
I am having a "Solve failed to lazily initialize a collection of role.... exception" in jpa. I understand that outside a session, when you want to retrieve a lazy collection if there is not session bound you will get this error, fine. But what I dont understand is if I have this spring controller(the code is not 100% correct, is just to explain my case):
#Controller
#Autowired
EnterpriseService enterpriseService ;
public List<Enterprise> getAll(){
List<Enterprise> enterprises = enterpriseService.getAll();
for(Enterprise enterprise:enterprises){
enterprise.getEmployees();
}
return enterprises;
}
When I call "enterprise.getEmployees()", I know there is not anymore a session but why when I try to do "enterprise.getEmployees()", why enterprise is treated like a jpa entity and not just like a normal bean?, I mean; for what I understand a jpa entity is treated like this inside a session but outside like in this case it should be treated like a normal java bean so the calling to enterprise.getEmployees() should be treated like the calling of a get method of a java bean and should not throw any lazy exception....
Maybe is because spring controller treats the enterprise objects like jpa entities and not just only like java beans? this behaviour is specific to spring controllers?
Thanks
An entity returned from an EntityManager is not necessarily an instance of your entity class, but a proxy class which extends your class. In many cases the same is true for the persistent properties of such entities (especially for those annotated with (One/Many)To(One/Many)).
For example if you are using field based access:
#Entity
public class Enterprise {
#OneToMany
private List<Employee> employees = new ArrayList<>();
public List<Employee> getEmployees() {
return employees;
}
}
Here the JPA provider will create a proxy class that extends Enterprise and remembers the previous state from the DB somehow. In addition it will change the employees list to its own implementation of List (which does not need to extend ArrayList).
Because the proxy class can "overwrite" your methods, it could know when you are calling getEmployees() and check for the session. But I don't think that this would happen here, as the method is not annotated with any JPA specific annotation.
In addition some frameworks like Hibernate do support byte code enhancement or byte code instrumentation. That changes the implementation of your class (in byte code) and replaces every access to employees with some provider specific code. I don't know if Spring JPA provides this, but this could lead to check for a session.
Otherwise any call to enterprise.getEmployees() should just return the current value of employees - without any check for the session and without the LazyInitializationException.
But calling enterprise.getEmployees().size() will try to initialize the list and check for the session - this could lead to the mentioned exception.
If you are using property based access things are a little bit different:
#Entity
public class Enterprise {
private List<Employee> employees = new ArrayList<>();
#OneToMany
public List<Employee> getEmployees() {
return employees;
}
}
Here the proxy class will not delegate to your implementation, but overwrite the getEmployees() method and return its own List implementation, without changing employees. Thus here it is possible to get a LazyInitalizationException for enterprise.getEmployees().
Remark: This describes how most JPA implementations are working - but as this is implementation specific some unusual frameworks could do things differently.
It can't do anything else. The only alternative would be to return an empty collection of employees, which would be much much worse: you would incorrectly assume that the enterprise has 0 employee, which is a valid, but completely incorrect result.
To realize how much worse it would be to do that, let's imagine a HospitalAnalysis entity, having a collection of DetectedDisease entities. And let's say you try to display the result of the analysis but forget to initialize the collection. The page would tell you that you're perfectly healthy and that you can safely go home, whereas in reality, you have a cancer, and the program has a bug. I'd much prefer the program to crash with an exception and be fixed rather than not starting my treatment.
Trying to access employees without having initialized the collection, and thus without knowing the actual collection of employees, is just a bug. This bug is signalled by throwing a runtime exception.
I have several concerns when trying to do DDD development with EF 4.2 (or EF 4.1) code first. I've done some extensive research but haven't come up with concrete answers for my specific concerns. Here are my concerns:
The domain cannot know about the persistence layer, or in other words the domain is completely separate from EF. However, to persist data to the database each entity must be attached to or added to the EF context. I know you are supposed to use factories to create instances of the aggregate roots so the factory could potentially register the created entity with the EF context. This appears to violate DDD rules since the factory is part of the domain and not part of the persistence layer. How should I go about creating and registering entities so that they correctly persist to the database when needed to?
Should an aggregate entity be the one to create it's child entities? What I mean is, if I have an Organization and that Organization has a collection of Employee entities, should Organization have a method such as CreateEmployee or AddEmployee? If not where does creating an Employee entity come in keeping in mind that the Organization aggregate root 'owns' every Employee entity.
When working with EF code first, the IDs (in the form of identity columns in the database) of each entity are automatically handled and should generally never be changed by user code. Since DDD states that the domain is separate from persistence ignorance it seems like exposing the IDs is an odd thing to do in the domain because this implies that the domain should handle assigning unique IDs to newly created entities. Should I be concerned about exposing the ID properties of entities?
I realize these are kind of open ended design questions, but I am trying to do my best to stick to DDD design patterns while using EF as my persistence layer.
Thanks in advance!
On 1: I'm not all that familiar with EF but using the code-first/convention based mapping approach, I'd assume it's not too hard to map POCOs with getters and setters (even keeping that "DbContext with DbSet properties" class in another project shouldn't be that hard). I would not consider the POCOs to be the Aggregate Root. Rather they represent "the state inside an aggregate you want to persist". An example below:
// This is what gets persisted
public class TrainStationState {
public Guid Id { get; set; }
public string FullName { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
// ... more state here
}
// This is what you work with
public class TrainStation : IExpose<TrainStationState> {
TrainStationState _state;
public TrainStation(TrainStationState state) {
_state = state;
//You can also copy into member variables
//the state that's required to make this
//object work (think memento pattern).
//Alternatively you could have a parameter-less
//constructor and an explicit method
//to restore/install state.
}
TrainStationState IExpose.GetState() {
return _state;
//Again, nothing stopping you from
//assembling this "state object"
//manually.
}
public void IncludeInRoute(TrainRoute route) {
route.AddStation(_state.Id, _state.Latitude, _state.Longitude);
}
}
Now, with regard to aggregate life-cycle, there are two main scenario's:
Creating a new aggregate: You could use a factory, factory method, builder, constructor, ... whatever fits your needs. When you need to persist the aggregate, query for its state and persist it (typically this code doesn't reside inside your domain and is pretty generic).
Retrieving an existing aggregate: You could use a repository, a dao, ... whatever fits your needs. It's important to understand that what you are retrieving from persistent storage is a state POCO, which you need to inject into a pristine aggregate (or use it to populate it's private members). This all happens behind the repository/DAO facade. Don't muddle your call-sites with this generic behavior.
On 2: Several things come to mind. Here's a list:
Aggregate Roots are consistency boundaries. What consistency requirements do you see between an Organization and an Employee?
Organization COULD act as a factory of Employee, without mutating the state of Organization.
"Ownership" is not what aggregates are about.
Aggregate Roots generally have methods that create entities within the aggregate. This makes sense because the roots are responsible for enforcing consistency within the aggregate.
On 3: Assign identifiers from the outside, get over it, move on. That does not imply exposing them, though (only in the state POCO).
The main problem with EF-DDD compatibility seems to be how to persist private properties. The solution proposed by Yves seems to be a workaround for the lack of EF power in some cases. For example, you can't really do DDD with Fluent API which requires the state properties to be public.
I've found only mapping with .edmx files allows you to leave Domain Entities pure. It doesn't enforce you to make things publc or add any EF-dependent attributes.
Entities should always be created by some aggregate root. See a great post of Udi Dahan: http://www.udidahan.com/2009/06/29/dont-create-aggregate-roots/
Always loading some aggregate and creating entities from there also solves a problem of attaching an entity to EF context. You don't need to attach anything manually in that case. It will get attached automatically because aggregate loaded from the repository is already attached and has a reference to a new entity. While repository interface belongs to the domain, repository implementation belongs to the infrastructure and is aware of EF, contexts, attaching etc.
I tend to treat autogenerated IDs as an implementation detail of the persistent store, that has to be considered by the domain entity but shouldn't be exposed. So I have a private ID property that is mapped to autogenerated column and some another, public ID which is meaningful for the Domain, like Identity Card ID or Passport Number for a Person class. If there is no such meaningful data then I use Guid type which has a great feature of creating (almost) unique identifiers without a need for database calls.
So in this pattern I use those Guid/MeaningfulID to load aggregates from a repository while autogenerated IDs are used internally by database to make a bit faster joins (Guid is not good for that).