I have a domain object called User:
class User{
String username;
String firstName;
String lastName;
Zipcode zip;
}
I also have a Zip Code object:
class Zipcode {
String zip;
String city;
String state;
Float lat;
Float long;
}
The zipcode table should never be modified as it contains static reference data prepopulated
A user belongs to one zipcode. The user enters the zipcode as part of the User creation.
How should I model the domain objects relationship? I would like like to make sure that GORM does not attempt to update zipcodes. I would like to make sure that the user only enters valid zipcode numbers. (Which are found in the zipcode table) How do I configure the constraints on the User object? In the controller, I do the following:
def userInstance = new User(params) // where params are form values
How do I set the proper zipcode on the object?
You would not let GORM manage the zip property (and restrict GORM from doing so at a second stage), at all.
That's what mfloryan's approach tells, too; however, his approach doesn't separate concerns, properly (separation of concerns paradigm): In the MVC (Model-View-Controller) pattern, it's not the controllers' task to "model" the data model, but it's the task of the data access layer (which is - in case of GORM - the domain classes theirselves).
Thus, the User class would be implemented like that:
class User {
String userName
String firstName
String lastName
String zip
ZipCode retrieveZipCode() {
ZipCode.findByZip(zip)
}
static constraints = {
zip nullable: false, blank: false, matches: /^\d{5}/,
/* not tested at my machine: */
validator: {
if(!retrieveZipCode(it)) {
return false
}
}
}
}
Note the retrieveZipCode() method. It's not called getZipCode() as, otherwise, Hibernate would throw an exception about a "missing setter method". You can also experiment with adding a zipCode property, a getZipCode() method (that does nothing or, alternatively, throws an exception), and adding the zipCode property to the transinients definition. - Everything of this (in any combination) will not work.
Also note the constraints definition: It matches when the zip consists of exactly five digits. (I believe that's the format of ZIP codes there in the USA.)
It should also make sure that the database contains an entry for the user's ZIP code (syntax not tested).
I've changed the ZipCode class slightly (partly, to avoid a compilation error):
class ZipCode {
String zip;
String city;
String state;
Float latitude;
Float longitude;
}
And finally, there's an integration test:
class UserTests extends GroovyTestCase {
def testUserCreation() {
User user = new User(
userName: "foo", firstName: "bar",
lastName: "baz", zip: "12345")
assert user.validate()
assert user.retrieveZipCode()
user.save()
}
}
Thanks
This sounds like more of an UI issue. Do a Zipcode object lookup in the controller and set the the object located on the user. Otherwise, I can't see how a Zipcode could have been altered upon creation of a user.
save = {
params.zip.id = Zipcode.findByZip(params.zip)
def userInstance = new User(params)
}
or
save = {
def userInstance = new User(params)
userInstance.zip = Zipcode.findByZip(params.zip)
}
You should include some validation logic (if the zip is incorrect) and also consider renaming params.zip to params.userProvidedZip or something like that.
use Domain event callback
transient beforeUpdate = {
// check to make sure that the zip code value remains the same
// and is never changed...
}
Related
Creating instances
I am new to DDD and wondering if the Factory that creates the Entity is responsible for creating the Value Objects. Here is a small example of what I have until this moment:
class User extends Entity {
public name: UserName;
constructor (name: UserName) {
this.name = name;
}
}
class UserName extends ValueObject {
public userName: string;
}
class UserFactory {
public create(string name) {
return new User(
new UserName(name)
);
}
}
I think that way the components that create an user (UserEntity) just need to pass the string to the factory and thats all. But on the other side this code is not following the Single responsibility principle. Maybe it is better to just pass the UserName value object directly?
class UserFactory {
public create(UserName userName) {
return new User(
userName
);
}
}
Validation
The other concept that is still unclear to me is the validation. Talking about the validation when creating the object (UserEntity). Is the UserFactory responsible for it? For example:
class UserFactory {
public create(UserName userName, UserLastName userLastName) {
if (userName == userLastName)
// throw validation exception
return new User(
userName,
userLastName
);
}
}
Image I added lastName to the UserEntity as ValueObject. I know it is dummy to compare the both names but just to give an example.
So is it correct that way - to remove the responsibility from the UserEntity or the following snippet is better:
class User extends Entity {
public name: UserName;
public lastName: UserLastName;
constructor (name: UserName, lastName: UserLastName) {
if (name == lastName)
// throw validation exception
this.name = name;
this.lastName = lastName;
}
}
The most interesting thing to me is when there is a change in the constructor of the Entity (add more required parameters to the constructor). I am searching for the approach that is going to cause the smallest number of changes as possible - using Factory pattern of just the constructor of the Entity? What are the biggest advantages in using Factory over the simple way - constructor (if there are).
I think you might be complicating things. The factory pattern is not really part of DDD, but it's a design pattern to use when building an object is complex or you want to hide some of the attributes that the Entity needs to work (for example in UIs, the elements might need some access to the class that does the rendering). There's a lot more info if you go to duckduckgo and search for design factory pattern
The examples you showed don't really require a factory. If all the factory is doing is passing parameters to a constructor, it's not adding anything.
About validation, the idea is that a constructor should never return successfully if an object is not usable, so in your examples, the null validations should be in the constructor of the object if the parameter cannot be null.
About value objects, again, why do you need a Factory? What benefit does it bring? I honestly cannot think of one case where it makes sense to have a Factory class. Sometimes, to make code a bit cleaner, one might use a factory method. For example, in Java the class Optional can only be constructed by calling the static builder method Optional.of() (which by the way, does some extra validation that only applies to that method).
TL;DR: use a Factory class if it brings a benefit, otherwise just instantiate class directly.
I want to add new field description to User entity. I can't use yo jhipster:entity User because it is forbidden. So, what I have to do?
If we need to store more information concerning a user than what JHipster provides by default, a few tweaks are needed.
To illustrate this, let’s assume we want to store the user’s phone number.
Creating a new entity in a One to One relationship with JHI_User
The best way to add information that is not handled by the default JHipster User is by using composition in a new entity linked to it with a One to One relationship.
After this entity is created, let’s call it UserExtra, the best way to handle its id is by mapping it to the JHI_User’s one. This way, our UserExtra will have the same id as the User’s, accelerating the different requests. To achieve this, you will need to use the #MapsId annotation :
public class UserExtra implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
#Column(name = "phone")
private String phone;
#OneToOne
#MapsId
private User user;
...
}
Note that the #GeneratedValue annotation on the id needs to be removed.
Updating the register HTML page to take this change into account
Now that an entity exists to store the phone number, we need to add an input in the register form to ask for the user’s phone number.
Nothing easier than that, just update webapp/app/account/register/register.html to add an input field bound to the variable already used to store the basic information (vm.registerAccount) :
<input class="form-control" id="phone" ng-model="vm.registerAccount.phone" placeholder="global.form.phone.placeholder" />
Updating ManagedUserVM
The registerAccount() function from java/com.mycompany.myapp/web/rest/AccountResource is the one receiving the request from the registration page. Its only parameter is a ManagedUserVM object containing the information initially contained in the vm.registerAccount variable from the client.
This ManagedUserVM class located in web/rest/vm has to be updated as well so that it holds the phone number sent by the client. The only thing to do here is adding the phone number attribute and its getter :
public class ManagedUserVM extends UserDTO {
// Default attributes omitted for brevity
private String phone;
...
public String getPhone() {
return phone;
}
}
Updating the registerAccount() function from AccountResource
The registerAccount() function now receives a ManagedUserVM object that also contains the phone number of the user. The only thing left to do is saving this phone number into a new UserExtra associated with the JHipster User.
To do so, we are going to add the phone parameter to the createUser() function from UserService. But first, add this parameter where this function is called in registerAccount() :
public ResponseEntity<?> registerAccount(#Valid #RequestBody ManagedUserVM managedUserVM) {
HttpHeaders textPlainHeaders = new HttpHeaders();
textPlainHeaders.setContentType(MediaType.TEXT_PLAIN);
return userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase())
.map(user -> new ResponseEntity<>("login already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
.orElseGet(() -> userRepository.findOneByEmail(managedUserVM.getEmail())
.map(user -> new ResponseEntity<>("e-mail address already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
.orElseGet(() -> {
User user = userService
.createUser(managedUserVM.getLogin(), managedUserVM.getPassword(),
managedUserVM.getFirstName(), managedUserVM.getLastName(),
managedUserVM.getEmail().toLowerCase(), managedUserVM.getLangKey(),
managedUserVM.getPhone());
mailService.sendActivationEmail(user);
return new ResponseEntity<>(HttpStatus.CREATED);
})
);
}
Updating the createUser() function from UserService
Finally, we update the service layer function that saves the JHI_User to now save the UserExtra as well. Rather than updating the existing function, I suggest you create a new one with the additional parameter. This way, updating the test classes isn’t necessary.
Do not forget to inject the UserExtra repositories :
#Inject
private UserExtraRepository userExtraRepository;
#Inject
private UserExtraSearchRepository userExtraSearchRepository;
...
public User createUser(String login, String password, String firstName, String lastName, String email,
String langKey, String phone) {
User newUser = new User();
Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER);
Set<Authority> authorities = new HashSet<>();
String encryptedPassword = passwordEncoder.encode(password);
newUser.setLogin(login);
// new user gets initially a generated password
newUser.setPassword(encryptedPassword);
newUser.setFirstName(firstName);
newUser.setLastName(lastName);
newUser.setEmail(email);
newUser.setLangKey(langKey);
// new user is not active
newUser.setActivated(false);
// new user gets registration key
newUser.setActivationKey(RandomUtil.generateActivationKey());
authorities.add(authority);
newUser.setAuthorities(authorities);
userRepository.save(newUser);
userSearchRepository.save(newUser);
log.debug("Created Information for User: {}", newUser);
// Create and save the UserExtra entity
UserExtra newUserExtra = new UserExtra();
newUserExtra.setUser(newUser);
newUserExtra.setPhone(phone);
userExtraRepository.save(newUserExtra);
userExtraSearchRepository.save(newUserExtra);
log.debug("Created Information for UserExtra: {}", newUserExtra);
return newUser;
}
https://jhipster.github.io/tips/022_tip_registering_user_with_additional_information.html
Add column to entity User.java:
#Column(name = "description")
private String description;
Modify method toString().
In UserDTO.java add:
private String description;
Generate getter and modify method toString().
Add liquidbase diff or add column.
Now is time to modify some webapp folder.
File user-managment.state.js find state user-managment.new and to entity: function () new return ,description: null
If you want to add this field to display find and modify files:
user-managment.html
user-managment-detail.html
user-managment-dialog.html
For example: <th><span data-translate="some.some.user.description">Description</span></th>
RPM1984 in this question speaks about POCO are "persistent ignorant" objects. But he doen´t speak about how much logic can hold. For example:
class Person {
public string FirstName { get; set; }
}
Or this:
class Person {
private string firstName = string.Empty;
public string Firstname {
get
{
return this.firstname;
}
set {
if (value.Length > 26)
{
throw new System.ComponentModel.DataAnnotations.ValidationException("Firstname is too long");
}
this.firstname = value;
}
}
}
Both are "persistent igonrant". The first one is for sure a POCO class. But is it the second a valid POCO? It has some logic but it could be persisted without problem and its logic is not more than a validation. Can it be considered POCO?
Thanks
Yes, the second one is a valid POCO, because it doesn't use a persistence specific detail. The whole point of POCOs is to say that a certain object doesn't depend on a db access library. If, for example, you would decorate Person with an EF specific attribute then, you would have to reference EF everywhere you'd use that class.
I am looking for advice on where to add validation rules for domain entities, and best practices for implementation. I did search and did not find what i was looking for, or i missed it.
I would like to know what the recommended way is for validating that properties are not null, in a certain range, or length, etc... I have seen several ways using an IsValid() and other discussions about enforcing in the constructor so the entity is never in an invalid state, or using preprocessing and postprocessing, and others using FluentValidation api, how invariants impact DRY and SRP.
Can someone give me a good example of where to put these sorts of checks, when using a App Service, Bounded Context, Domain Service, Aggregate Root, Entity layering. Where does this go, and what is the best approach?
Thanks.
When modeling your domain entity, it is best to consider real-world implications. Let's say you are dealing with a Employee entity.
Employees need a name
We know that in the real-world an employee must always have a name. It is impossible for an employee not to have a name. In other words, one cannot 'construct' an employee without specifying its name. So, use parameterised constructors! We also know that an employees name cannot change - so we prevent this from even happening by creating a private setter. Using the .NET type system to verify your employee is a very strong form of validation.
public string Name { get; private set; }
public Employee(string name)
{
Name = name;
}
Valid names have some rules
Now it starts to get interesting. A name has certain rules. Let's just take the simplistic route and assume that a valid name is one which is not null or empty. In the code example above, the following business rule is not validated against. At this point, we can still currently create invalid employees! Let's prevent this from EVER occurring by amending our setter:
public string Name
{
get
{
return name;
}
private set
{
if (String.IsNullOrWhiteSpace(value))
{
throw new ArgumentOutOfRangeException("value", "Employee name cannot be an empty value");
}
name = value;
}
}
Personally I prefer to have this logic in the private setter than in the constructor. The setter is not completely invisible. The entity itself can still change it, and we need to ensure validity. Also, always throw exceptions!
What about exposing some form of IsValid() method?
Take the above Employee entity. Where and how would an IsValid() method work?
Would you allow an invalid Employee to be created and then expect the developer to check it's validity with an IsValid() check? This is a weak design - before you know it, nameless Employees are going to be cruising around your system causing havoc.
But perhaps you would like to expose the name validation logic?
We don't want to catch exceptions for control flow. Exceptions are for catastrophic system failure. We also don't want to duplicate these validation rules in our codebase. So, perhaps exposing this validation logic isn't such a bad idea (but still not the greatest!).
What you could do is provide a static IsValidName(string) method:
public static bool IsValidName(string name)
{
return (String.IsNullOrWhiteSpace(value))
}
Our property would now change somewhat:
public string Name
{
get
{
return name;
}
private set
{
if (!Employee.IsValidName(value))
{
throw new ArgumentOutOfRangeException("value", "Employee name cannot be an empty value");
}
name = value;
}
}
But there is something fishy about this design...
We now are starting to spawn validation methods for individual properties of our entity. If a property has all kinds of rules and behavior attached to it, perhaps this is a sign that we can create an value object for it!
public PersonName : IEquatable<PersonName>
{
public string Name
{
get
{
return name;
}
private set
{
if (!PersonName.IsValid(value))
{
throw new ArgumentOutOfRangeException("value", "Person name cannot be an empty value");
}
name = value;
}
}
private PersonName(string name)
{
Name = name;
}
public static PersonName From(string name)
{
return new PersonName(name);
}
public static bool IsValid(string name)
{
return !String.IsNullOrWhiteSpace(value);
}
// Don't forget to override .Equals
}
Now our Employee entity can be simplified (I have excluded a null reference check):
public Employee
{
public PersonName Name { get; private set; }
public Employee(PersonName name)
{
Name = name;
}
}
Our client code can now look something like this:
if(PersonName.IsValid(name))
{
employee = new Employee(PersonName.From(name));
}
else
{
// Send a validation message to the user or something
}
So what have we done here?
We have ensured that our domain model is always consistent. Extremely important. An invalid entity cannot be created. In addition, we have used value objects to provide further 'richness'. PersonName has given the client code more control and more power and has also simplified Employee.
I built a library that can help you.
https://github.com/mersocarlin/ddd-validation
Helllo..... I am quite new in Microsoft Enterprise Library Validation Framework. My question is that I want same validation condition in two different RuleSet.
Is it possible to put two rule set with in the same Validator like below
/// <summary>
///
/// </summary>
[StringLengthValidator(1,25,Ruleset="DetailRuleSet",Ruleset="MainRuleSet",Tag="First Name")]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
or I have mentioned it by writing the same in two time with different ruleset name like below
/// <summary>
///
/// </summary>
[StringLengthValidator(1,25,Ruleset="DetailRuleSet",Tag="First Name")]
[StringLengthValidator(1, 25, Ruleset = "MainRuleSet", Tag = "First Name")]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
Any help would be appreciated!!
First a disclaimer: I haven't worked so much on the Enterprise Library Application Validation Block, however, having been a programmer for over a decade and a half, and having used Validation models from ASP.NET to MVC Data Annotations, I can tell you that the API for validation in Enterprise Library is pretty similar. It took me about 20 minutes to download the Enterprise Library source code and look up the answer to this question. So, here's my answer.
Yes, you can apply more than one validation attribute to a given model property, each validation attribute specifying a different rule set.
However, in such a case, you will have to explicitly invoke the validator on the model type for that particular rule set.
If you do not do that, the Enterprise Library will execute the validator for the default rule-set.
In the context of your example, you can say:
StringLengthValidator(1,25,Ruleset="DetailRuleSet",Tag="First Name")]
[StringLengthValidator(1, 25, Ruleset = "MainRuleSet", Tag = "First Name")]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
However, in this case, you have to specifically invoke one of the rule-sets for validation, like so:
var yourModelObjectValidator =
yourValidatorFactory.CreateValidator<YourModelClass>("yourRuleSetName");
var yourModelObject =
new YourModelClass { Foo = "foo", Bar = "bar", Gar = 2 };
var results =
yourModelObjectValidator.Validate(yourModelObject);
if (!results.IsValid)
{
foreach(var result in results)
{
/* run the state machine, do whatever, print */
}
}
If you do not specify the rule set name like we did above, the Enterprise Library will execute your validations in the context of a default rule set which has no name, and hence none of the two rules you specified above using the validation attributes will get executed.
UPDATE
Based on your comment, I see what your real question is.
Your question then really is: Can I specify more than a single rule-set in a single validation attribute declaration?
The answer is as simple as the question: No. Because the property RuleSet is declared simply as string and not as IEnumerable<string> in the BaseValidationAttribute class, the mother of all ValidatorAttribute classes in the EntLib source code.