I was wondering if there was a more elegant way in managing contact details for an individual. Forget the SQL side of things for a moment, I am intrigued in how one would perhaps attempt to drive this via a DDD approach.
I was fooling around with some code in an effort to get comfortable with DDD as a whole and came up with the following which seems awful.
Firstly, I have an object called Person (simplified for the purpose of this post) where I envision methods to add and essentially manage different methods of communicating an individual.
public class Person
{
public Person()
{
this.ContactDetails = new List<ContactDetails>();
}
public void AssociateContactDetails(ContactDetails contactDetails)
{
var existingContactDetails = this.ContactDetails.FirstOrDefault(x => x.ContactType == contactDetails.ContactType);
if (existingContactDetails != null)
{
this.ContactDetails.Remove(existingContactDetails);
}
this.ContactDetails.Add(contactDetails);
}
public IList<ContactDetails> ContactDetails { get; private set; }
}
Two approaches spring to mind. One where I have a fairly simple object like the one below which is quite generic (using the term loosely).
public enum ContactType
{
Email, Telephone, Mobile, Post
}
public class ContactDetails
{
private readonly ContactType contactType;
private readonly string value;
public ContactDetails(ContactType contactType, string value)
{
this.contactType = contactType;
this.value = value;
}
public ContactType ContactType
{
get { return this.contactType; }
}
public string Value
{
get { return this.value; }
}
}
But then I put myself into a corner with this approach as although it works well for trivial items such as email and telephone, when it comes to something like postal a string doesn't quite cut it. Therefore, after this I am heading towards the approach of having each mechanism of communication to represented by its own type, i.e.:
public class Post
{
public Address PostalAddress { get; set; }
}
public class Mobile
{
public string MobileNo { get; set; }
}
public class Telephone
{
public string AreaCode { get; set; }
public string TelephoneNo { get; set; }
}
public class Email
{
public string EmailAddress { get; set; }
}
Each type can then represented as a collection or single instance in the Person class? Seems long winded however is perhaps more readable and maintainable.
The question I guess is if there is a more elegant way in implementing such a feature and whether someone can point me in the direction of a good example similar to this. I imagine this is a common thing / problem to overcome.
Cheers, DS.
We know for sure what are the contact methods "email, "phone" and "address", so having identified those what we have to do first is to model those concepts taking into account what they really are. Let's take "email" as example and see what it really is in order to model it properly. It is a value object (an immutable object) that once created it will never change just as an integer number is an immutable object as well. The difference is that for modelling an integer number we can use the int type provided by any programming language, but the question is what class do we use for modelling en Email? Most of people would use a String instance to model an Email, but is this OK? In order to answer it let's see what is the protocol (the set of messages) a String object knows to response: "charAt(anIndex), replace(aString, anotherString), etc... ". Imagine that if we model an email by using a String class we could ask the email "replace(aString, anotherString)". That sounds weird, that message should not be part of the behavior an email should expose to other objects. Also so so important we said an email is immutable to it cannot expose behavior that at the end change it state. So it makes visible that we need to create a whole new abstraction to model an email and what is it? The Email class finally comes in!!! I know you suggested it but I just wanted to let you see why we need an Email class created.
First of all this is DDD (object oriented) so FORGET avoid setters and getters. In the email class you created you expose a setter method meaning that you can change the email and it contradicts with the nature of what an email is (immutable). An email is immutable from the momento it is created:
Email.fromString("monicalewinsky#gmail.com");
that is the same as doing
new Email("monicalewinsky#gmail.com");
The fromString method is a factory method that adds semantic to our domain model. This is very common in smalltalk instead of calling the constructor directly. Are we done??? Not at all. An email instance should be created as long as it is valid so the email class should assert the string from which is created is valid:
Email(String anEmailStringRepresentation) {
assertIsValid(anEmailStringRepresentation);
}
assert is valid should verify it is actually an email string representation. This is that is has only one # character, its local part is valid and then its domain part is valid. You can check the wikipedia for email address to understand better how it is composed.
Remember always that programming is a learning process, as long as we understand a domain better and better we reflect that domain in the code and it always must be consistent with the real world! Our Email class should look like more or less like:
class Email {
String value;
Email(aString) {
value = aString;
}
public String getLocalPart()
public String getDomainPart()
public String asString()
public boolean equals(anObject)
public static Email fromString(aString)
}
That's it. It happens the same with PhoneNumber. It is also an inmmutable object and you should create a class with its own protocol. Remember never use set/get as you showed up if we are doing DDD. I don't think you need two value objects Telephone and Mobile since those are polymorphic objects and you could model a mobile phone number or a home phone number with the TelephoneNumber abstraction. It's like modelling a credit card. At the end you will end up and understand that the class CreditCard is enough and a better design than having several class such as Visa, MasterCard, and so on.
Let's skip the Address class and let's go back to your problem now.
So far we have identified and created properly all the value objects we need. Now we need to create an abstraction for representing an email, phonenumber, address as contact methods and if we keep loyal to the domain language we could say:
ContactMethod.for(Email.fromString("monica#gmail.com"));
or
ContactMethod.for(PhoneNumber("34234234234"));
etc
so our ContactMethod would look like:
class ContactMethod {
static EMAIL = 1;
static PHONE_TYPE = 2;
static ADDRESS_TYPE = 3;
String type;
String value;
ContactMethod(int aType, String aValue) {
type = aType;
value = aValue;
}
String getType()
String getValue()
public static ContactMethod at(Email anEmail) {
return new ContactMethod(EMAIL, anEmail.asString());
}
public static ContactMethod at(PhoneNumber aPhoneNumber) {
return new ContactMethod(PHONE_TYPE, aPhoneNumber.asString());
}
public static ContactMethod at(Address anAddress) {
return new ContactMethod(ADDRESS_TYPE, anAddress.asString());
}
}
See that ContactMethod is also an immutable class, actually a rule of thumb is that an Aggregate root should have ideally only an aggregation of value objects.
This is finally how your Person class would look like:
class Person {
List<ContactMethod> contactMethods;
contactedAt(Email anEmail) {
contactMethods.add(ContactMethod.at(anEmail));
}
contactedAt(PhoneNumber aPhoneNumber) {
contactMethods.add(ContactMethod.at(aPhoneNumber));
}
contactedAt(Address anAddress) {
contactMethods.add(ContactMethod.at(anAddress));
}
}
On my journey of learning DDD sometimes I see patterns instead of problems... an interesting example Everything seems to be an Aggregate Root is another answer I had provided regarding a menu, which had different categories such as starter, main, desert etc.
I had modeled this implicitly as a category string. After i posted there was a second answer where someone suggested modeling these as explicit lists of:
Menu {
List<Food> starters;
List<Food> entrees;
List<Food> desserts;
List<Food> drinks;
}
In this way, the entire concept of the category for a food was removed, this was enlightening for me and saw a different way of modeling and in this case reducing complexity.
My view is to try and model the code so that if I sat down with the business expert (who is not a developer) and showed them the use case code from a high level person.SetMobileNumber("078321411", Countries.UK) they would be able to understand it:
public void HandleUpdateMobileCommand(UpdateMobileNumber command)
{
// repositories, services etc are provided in this handler class constructor
var user = this.UserRepository.GetById(command.UserId);
user.SetMobile(command.number, command.country);
this.UserRepository.Save(user);
// send an SMS, this would get the number from user.Mobile
this.SmsService.SendThankYouMessage(user);
}
Or even better, you could have a MobileUpdated event get fired when you update the user mobile, to which some code somewhere else (which is an expert on sending SMS messages, and nothing else) is listening to these events - for me this is the real power of DDD of breaking down code in to expert systems.
So in summary, I think your second suggestion of explicitly modeling with Post, Mobile, Landline and Email makes most sense.
I wouldn't say this a DDD domain or not as there isn't enough information on any complex logic (or multi-user race conditions) that you require, just to mention don't forget that you may be better writing a CRUD app if that makes more sense in this situation.
There's this central idea in DDD that domain modelling must take shape through discussion with domain experts. If you're making up these class names out of thin air, chances are they won't exactly match your real domain. Trivial ones such as Email or Telephone should be correct, but maybe for others you want feedback from an expert first.
Generally speaking, it's a good idea indeed to favor semantically rich modelling with dedicated value objects over primitive types. In C# it comes at a cost though since the amount of boilerplate code needed is huge (unlike F# for instance). This is why I usually prefer to do it only when the type has more than a single property or when there are specific construction rules or invariants to it.
One good thing you can do is model your types as immutable Value Objects. So something like:
public class Telephone
{
public string AreaCode { get; set; }
public string TelephoneNo { get; set; }
}
Might become:
public class TelephoneNumber
{
private string areaCode;
private string subscriberNumber;
private TelephoneNumber()
{
}
public TelephoneNumber(string areaCode, string subscriberNumber)
{
this.AreaCode = areaCode;
this.SubscriberNumber = subscriberNumber;
}
public string AreaCode
{
get
{
return this.areaCode;
}
private set
{
if (value == null)
{
throw new ArgumentNullException("AreaCode");
}
if ((value.Length <= 0) || (value.Length > 5))
{
throw new ArgumentOutOfRangeException("AreaCode");
}
this.areaCode = value;
}
}
// Etc.
}
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 11 months ago.
Improve this question
What is the best practice respecting the encapsulation?
I am using code first strategy with Entity Framework in .NET 6.
public class Employee
{
[Required]
public string Name { get; private set; }
public void SetName(string value)
{
this.Name = value;
}
}
or
public class Employee
{
private string _name;
[Required]
public string Name {
get { return _name; }
set { _name = value; }
}
}
or
public class Employee
{
[Required]
public string Name {get;set;}
}
Or is there a better way?
Thanks!
It is entirely personal preference and working through the scenarios you expect to encounter and how you want to safeguard or streamline them.
As a general rule I personally advocate for simplicity. A simple domain that is easy to understand is easy for other developers and consumers to pick up or otherwise be instructed. Often these decisions are made to try and restrict developers so-as to silo the domain so that UI developers for example either cannot directly modify data, or try and tightly control access. This may be necessary in very large projects/teams and can work provided your "gate keepers" can keep updates regular and consistent so that everyone can do what needs to be done, but often due to time constraints or responsibilities changing hands (gatekeepers leave and get backfilled by others that don't understand or agree) then bypasses inevitably leak into the model just leading to a confusing and unnecessarily complicated mess.
When it comes to the domain, I generally follow a more DDD-based approach similar to your first example, except I only use methods where I expect that there is a validation or specific combination of state that the entity can enforce itself. The responsibility for mutator methods like this either fall on the entity or the repository. (As I typically use a repository pattern)
For a value that can just change and might have simple validation or none at all, I will just use public setters. For no validation:
public string SomeValue { get; set; }
for basic validation that the entity can validate itself, using either attributes or validation logic inside the setter:
private string _someValue;
public string SomeValue
{
get { return _someValue; }
set
{
if (string.IsNullOrEmpty(value)) throw new ArgumentException("SomeValue is not optional.");
_someValue = value;
}
}
Often, Updates to state involve changing more than one thing where the combination of data should be validated together against the current remainder of the entity state. We don't want to set values one at a time because this means that the entity state could be left in an invalid state, or there is no guarantee that a caller will not simply set one value, ignoring the fact that the other values are technically invalid. As a very rough example of the concept, without getting into validation, it would be updating an address. Sure, it is possible that we may want to make a correction to a single address field, but typically if we are changing one address field we will most likely be invalidating the rest. For example, if I have an address that contains a Street Name, Number, City, PostCode, and Country, changing just the city or just the country would most often make the address completely invalid. In these cases I would use a Setter method to encapsulate updating an address:
public string Country { get; internal set; }
public string City { get; internal set; }
public string PostCode { get; internal set; }
public string StreetName { get; internal set; }
public string StreetNumber { get; set; }
public void UpdateAddress(string country, string city, string postCode, string streetName, string streetNumber)
{ // ...
}
It might be fine to allow them to just change the street number on it's own, or possibly even the street name without calling UpdateAddress so these might have public setters. City and Country might be FK values (CityId/CountryId) so there would be even less need to update these independenty. Simply having this method gate-keep the setting of the value should send a clear message to developers that they should be ensuring the complete and valid address details are sent at once, not relying on them correctly chaining piecemeal updates.
Where I might want to validate changes against existing data state, I would use an Internal setter, and have the update method as part of the Repository. For example if I want to allow them to update a Name, but ensure the name is unique. The repository has access to the domain, so I find it's a good location for this responsibility:
public void UpdateUserName(User user, string newName)
{
if (user == null) throw new ArgumentNullException("user");
if (string.IsNullOrEmpty(newName)) throw new ArgumentNullException("newName");
if (user.Name == newName) return; // Nothing to do.
var nameExists = _context.Users.Any(x => x.Name == newName && x.UserId != user.UserId);
if (nameExists) throw new ArgumentException("The name is not unique.");
user.Name = newName; // Allowed via the internal Setter.
}
It would be expected that if this was talking to a UI that the UI would validate that the name was unique prior to saving, but persistence should validate in case this can be called by other avenues like APIs, where things like unique constraints on the DB serve as the final guard.
Similarly, when it comes to creating entities, I will use factory methods much like the above in the Repository classes to do things like CreateAddress(...) which ensure that address entities are not simply newed up and filled adhoc. This ensures that when an entity is created, all required fields & relationships are provided and filled. The objective of this approach is to help ensure that from the point an entity is created and at every point through its mutation it is in a valid and complete state.
Hopefully that gives you some food for thought on the subject. Ultimately though you should look at what is important for your particular scenario and what real and actual problems you want to address. Don't get too caught up on trying to ward off hypothetical worst-case scenarios and ending up with something so rigid that it negatively impacts your coding responsiveness.
I typed this out in Notepad++ real quick so please forgive any typos/mistakes. If it's possible, I'd be getting rid of some repetitive work (i.e. a long case statement). Not a huge deal but I'm curious if it's possible and if so, how bad would it be to actually implement the code.
jsonFromWebpage = {
StatusUpdate: {
QueryType: "SomeClassName",
LocalCount: 5,
RemoteCount: 5
},
StatusUpdate: {
QueryType: "AnotherClass",
LocalCount: 29,
RemoteCount: 30
}
}
// Model
public class StatusUpdate
{
public string QueryType { get; set; }
public int LocalCount { get; set; }
public int RemoteCount { get; set; }
}
// Controller
public IActionResult GetStatusUpdate([FromBody] List<StatusUpdate> status)
{
_service.GetStatusUpdate(status);
return status
}
// Service
public List<Status> GetStatusUpdate(List<StatusUpdate> status)
{
foreach(var s in status)
{
var typeArgument = s.QueryType; // <--- Is there a way for this...
status.CurrentCount = GetTotalCount<typeArgument>(); // <--- to work here?
status.RemoteCount = thisworksfineforotherreasons(s.QueryType);
}
}
// Repo
public int GetTotalCount<T>() where T: class
{
var result = _db.GetCount<T>();
return result;
}
EDIT
First, thank you to everyone that has responded. Having read everything so far, I wanted to give a little more context. Here's a different take on the example:
// View
<div class="col-12">
<div class="api-types">History</div>
<div class="progress-bar">50 out of 50 copied</div>
</div>
<div class="col-12">
<div class="api-types">Users</div>
<div class="progress-bar">25 out of 32 copied</div>
</div>
// -- View javascript
var types = [];
$(".api-types").each(function (c, i) {
types.push({ ApiAndClassName: $(i).text() });
});
pushToController(JSON.stringify(types));
// Controller
public IActionResult GetSyncStatus(List<SyncStatusVM> status)
{
_service.GetSyncStatus(status);
return Json(status);
}
// Service
public List<SyncStatusVM> GetSyncStatus(List<SyncStatusVM> status)
{
foreach(var s in status)
{
// LocalCount
var magicTypeFigurator = s.ApiAndClassName
s.LocalCount = _repo.GetCount<magicTypeFigurator>(); <-- "this is a variable but should be a type..."
// Remote
var url = $"https://api.domain.com/{s.ApiAndClassName.ToLower()}"
s.RemoteCount = FetchCountFromApi(url);
}
return status;
}
// Repository
public long GetCount<T>()
{
var result = _orm.Count<T>();
return result;
}
// Models
public class SyncStatusVM
{
public string ApiAndClassName { get; set; }
public int LocalCount { get; set; }
public int RemoteCount { get; set; }
}
public class History
{
public long Id {get;set;}
public DateTime CreatedDate {get;set;}
public string Message {get;set;}
}
public class Users
{
public long Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
Using this code, I can just create a section in the view and a class for each type. The class is reused by the ORM and desearializing from the API. The most cumbersome point is having a case statement in the controller that calls the generic method with the correct type, based on the "ApiAndClassName". I could edit the ORM so it's string based instead of generic but I don't like that method for various reasons. I could turn the case statement into a collection in the controller or just move it to the service layer but what I have in place already works. I could also just refactor so the view builds from a collection but there are other data points where that wouldn't be the best option. Unless there's something I'm missing, the generic argument from string thing kinda makes sense. It's a fringe case... and kinda just curious if it can be done well enough.
Generally strong typsisation is your friend. Compile time type checks are a feature, not a enemy to be fought. Without them or with too agressive casting, we get the JavaScript and PHP examples from this comic.
For work with weakly typed langauges or WebServices, .NET has the ExpandoObject. The data can be stored in it, then later transfered into the proper type of instance. Also it looks like your case would fall into JSON deserialisation, wich is a well established code.
Generic is the wrong term. Generics are usually about the type still being known at compile time, so the compile time type checks still work. You are explicitly about the type not being known at compile time, only at runtime. This is very distinct from a generic. Dynamic Types are the proper term afaik. But to not mix it up with the type Dynamic (yes, naming here becomes really confusing).
Reflection is the droid you are looking for. For most purposes, the name of a class or field does not exist at runtime. It is primarily there for you and the compiler to communicate. Now Reflection is the exception. It is all about getting stuff (like instances or property/fields) based on a string representation of their name. The nessesary metadata is baked into the .NET Assemblies, as much as the COM support. But as I support strong typisation, I am not a friend of it.
switch/case statements can usually be replaced with a collection of some sort. Cases are really just a hardcoded way to check a collection of constants. You use the case identifier as the key and whatever else you need for the Value. You can totally use Functions as the value (thanks to delegates). Or the Type type, you then use for the instance creation.
But for your case it sounds like all of this is wrong. Bog standart Inheritance - Inheritance might be the real droid you are looking for. A JSON service would not usually give you different instance in a single collection, unless those instances are related in some way. "SomeClassName" and "AnotherClass" should have another ancestor. Or in fact, they should even be just one class - QueryType is simply a string field of said class.
Assuming that you have a way to map strings to Type objects, yes: you can use MethodInfo.MakeGenericMethod():
var totalCount = (int) (
GetType()
.GetMethod("GetTotalCount")
.MakeGenericMethod(MapStringToType(s.QueryType))
.Invoke(this, null)
);
This assumes the presence of a method Type MapStringToType(string) in the local scope.
One way to map types would be to use a Dictionary<string, Type> and fill it with the allowed types and their respective names that will be used in the JSON data to refer to them.
I've been reading about DDD and am still confused about aggregate root.
Imagine that I have a situation similar to a blog, where people can create posts and add comments to other posts.
Rules:
-Everybody needs to have an account to add post or comment
-Users are able to delete their own comments only
With that in mind, I would need the following objects:
-Post
-PostComment
-User
So, I created only the Post object as aggregate root and added some business logic to it
public class User : EntityBase
{
public string Name { get; set; }
public string Avatar { get; set; }
}
public class Post : EntityBase, IAggregate
{
public string Title { get; set; }
public string Content { get; set; }
public User Creator { get; set; }
private IList<PostComment> Comments { get; set; }
public void AddComment(PostComment comment)
{
this.Comments.Add(comment);
}
public void DeleteComment(PostComment comment, int userId)
{
if (comment.Creator.Id != userId)
throw new Exception("You cannot delete a comment that is not yours. blablabla");
this.Comments.Add(comment);
}
public IList<PostComment> GetComments()
{
return this.Comments;
}
}
public class PostComment : EntityBase
{
public string Comment { get; set; }
public User Creator { get; set; }
}
Am I doing this correctly? I mean, is the business logic in the right place? Or I should've made PostComment as aggregate root too and added the logic of add/delete in it?
Warning: it's difficult to reason about DDD using toy problems. Especially in your core domain, the point of all of this work is that you can customize things to meet your local needs. If you didn't need a bespoke solution, you'd just buy some off-the-shelf solution, integrate and get on with it.
Or I should've made PostComment as aggregate root too and added the logic of add/delete in it?
Maybe. Aggregates are best thought of as atoms, you load the entire aggregate, make your changes, save the results.
So if you find yourself with many concurrent attempts to modify the same aggregate, then you have to deal with a bunch of contention issues. Alice can't change her comment while Bob is changing his; we have to do them one at a time (to avoid losing changes).
On the other hand, if each comment is an aggregate of its own, then Bob and Alice can make their changes in parallel, without needing to rerun the "business logic" because the other person's change happened first.
Which is great, when it is free. But it isn't free -- the cost you pay is that the information is now distributed, and you have to deal with the fact that the changes have different timing. You'll sometimes see "eventual consistency" used here -- because the authoritative information is distributed, there will be times where not all of the observers have the same sets of changes.
In most domains, this is fine: race conditions don't exist. But trying to perform an all or nothing change across distributed data is a nightmare.
On the other hand, if you are willing to accept that changes happen at different times, then separating the aggregates out is fine.
Example: Twitter. Bob tweets something dumb. Alice tweets that Bob is dumb, with a link to his tweet. Bob deletes his tweet. And that's all fine, because we're comfortable with the fact that Alice's tweet has a link to something that is no longer available.
It is often the case that information that comes from the outside world can be its own aggregate, because what we are really doing at that stage is caching data, which is already stale by the time we receive it.
You may also want to review Mauro Servienti's talk All Our Aggregates Are Wrong, which discusses the heuristics for breaking down an aggregate into smaller pieces.
Am I doing this correctly? I mean, is the business logic in the right place? Or I should've made PostComment as aggregate root too and added the logic of add/delete in it?
Partially! I consider the logic is in the right place and PostComment should not be an aggregate root. But if you wants to take off more about DDD I consider that there are some another points to review before continue. I hope I can help you some way in the explanations bellow.
I have reviewed the code and refactored it to explain some points you can reconsider. Try to read it, compare and understand before read my explanation below.
// you can simplify your DomainModel removing the IAggregate plus adding generics
public abstract class Entity<T>
{
public T Id { get; set; }
}
// this is an Aggregate Root
public class Person : Entity<int>
{
public string Name { get; set; }
public string Avatar { get; set; }
public override string ToString()
{
return Name;
}
}
//this is an Aggregate Root
public class Post : Entity<int>
{
private List<Comment> _comments = new List<Comment>();
public string Title { get; set; }
public string Content { get; set; }
public Person Author { get; set; }
public IReadOnlyList<Comment> Comments => _comments;
public void Reply(Comment comment)
{
_comments.Add(comment);
}
public void Delete(Comment comment, int personId)
{
if (!AreSame(comment.Author, personId))
throw new Exception("You cannot delete a comment that is not yours. blablabla");
_comments.Add(comment);
}
private bool AreSame(Person author, int personId)
{
return author.Id == personId;
}
public override string ToString()
{
return Title;
}
}
// this is a Value Object part of Post Aggregate
public struct Comment
{
public DateTime Date;
public string Text;
public Person Author;
public Comment(DateTime date, string text, Person author)
{
Date = date;
Text = text;
Author = author;
}
public override string ToString()
{
return $"{Date} - {Author}: {Text}";
}
}
If the PostComment is part of Post Aggregate, it can't be an EntityBase, because each Aggragate should have only one root (Id). You're modeling a domain where a Post may have N Comments. You can consider the PostComment as a Value Object instead an Entity removing his Id.
You should pay attention about the names you are using. Try to sound more natural. It is called, ubiquitous language, the words everybody speak.
User is a description that just have a sense in system's context, in other words, you should have a User if you dealing with Security or Authentication contexts, in a Blog Context you have a Person acting as Author.
Increase readability using terms your users says. Reply may be more natural than AddComment.
public void Reply(Comment comment)
{
_comments.Add(comment);
}
Increase readability adding names for your conditions:
public void Delete(Comment comment, int personId)
{
if (!AreSame(comment.Author, personId))
throw new Exception("You cannot delete a comment that is not yours. blablabla");
_comments.Add(comment);
}
private bool AreSame(Person author, int personId)
{
return author.Id == personId;
}
We just received a phase 1 release from a vendor to translate an archaic PowerBuilder application into C# MVC with Angular 5 (we have an Angular guy that has already mostly rewritten the front end in 7 so the security concerns from 5 are a nonissue). Since the statement of work only required them to reproduce the application there are next to zero validations on input because there wasn't much, if any, on the original application.
I have recently done some research into FluentValidation and like it for its reusability later in applications that will use the same overall data. However, looking at this code the models in the MVC are not normalized like they probably should be and so we have dozens of models that likely could be normalized out so that there would be less overlap in data fields such as First Name, Last Name, Address, Business Address etc.
I have basic experience with generics and reflection and have supported a few more advanced examples in the past. So I was trying to find some way to utilze these two concepts to make the validators more dynamic.
I was unable to find much in the way of more advanced FluentValidation examples other than the basic hard connection to a given named model. I have tried to use the generic T in place of the model but was unable to bridge the gap and access the object being passed into the validation.
public class FormValidator : AbstractValidator<ModelExample>
{
public FormValidation()
{
}
}
//tried to do something like this but wasn't able to access the .HasProperties. Although I was able to access the GetProperties,
//having trouble implementing it into the RuleFor however.
public class FormValidation<T> : AbstractValidator<T>
{
RuleFor(x => x.GetType().GetProperty(nameof({something if it exists}).{check stuff is valid}
{
public class ModelExample
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class OtherModelExample
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
My end goal would be to be able to pass related objects into a given validator and it would be able to determine if the properties existed and act accordingly.
This may be an issue where I don't really know how to ask the question in Google, I tend to have issue wording things in a way where it brings up what I would expect.
This also may not even be possible but if it could save me from writing a series of hard coupled validators that I might have to rewrite later if we ever are allowed to normalize the data flow it would be of great help.
Any articles or documentation with more advanced examples than the simple ones I find would be of great use even beyond this project. Most of the tutorials I find are very basic examples and I sometimes have a hard time picturing them in "real" code application.
Thanks
Instead of creating generic validators for a whole model, have you considered the reverse and creating them for each property?
If you use custom property validators you can specify the validator logic once, and then simply create a validator class per view model.
eg:
class Program
{
static void Main(string[] args)
{
var person = new Person
{
Name = "Ada",
NickName = "A"
};
var validator = new PersonValidator();
var result = validator.Validate(person);
//Should be a problem with the NickName
}
}
class Person
{
public string Name { get; set; }
public string NickName { get; set; }
}
class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Name).SetValidator(new NameValidator());
RuleFor(x => x.NickName).SetValidator(new NameValidator());
}
}
public class NameValidator : AbstractValidator<string>
{
public NameValidator()
{
RuleFor(x => x).Must(x => x.Length > 1)
.WithMessage("The name is not long enough");
}
}
This is probably a safer option too, as it's opt in rather than implicit.
This question was for a Java project I'm working on but could apply to C# too.
Anyway, so I have an MVC web project. In it, I have three "layers" for my data.
com.example.model.dao
com.example.model.entities
com.example.model.service
So dao is my low-level database classes. Things like Hibernate wrappers, etc.
entities are my POJO's and service is my business logic.
Now let's say one of those POJO's is User. In User, it maps to a database table called users. This table (and POJO) has two fields, firstname and lastname. OK, so I want to put a method somewhere called getFullName that simply concatenates the first and last name.
So where should this method go? I thought about putting it in the POJO itself. But since sometimes we use tools to generate POJO's from a database, custom logic there could be overwritten. And is this a business process anyway?
Should I put it in my service implementation?
Thanks for your suggestions.
in c# I would use a partial class (which resolves "generated class" problems : of course, your generated POCOs would need to be partial)
public partial class User {
public string GetFullName() {
return string.Format("{0} {1}", FirstName, LastName);
}
}
Solution which wouldn't work in Java... as partial classes don't exist !
So the "most appropriate" solution wouldn't probably be the same for the 2 languages.
You should implement custom business logic in the business layer. In this case it should be in your service layer as you are generating your POJOs.
I normally put that type of methods in the entity itself, but since you say it could be overwritten, you could use a helper class for the entity.
class UserHelper {
String getFullName() {
...
}
... more methods
}
I don't see getting a person's full name as a business process.
As many of the developers around here, Im very strict with Design Patterns, Best Practices, and Standards, but ...
...there is always an exception to rules, or to be more exact to guidelines.
Developers usually put that kind of functions on the logic layer, but, in some cases, its OK to add it in the Plain Old (Java / C# / ...) Objects.
Pseudocode:
class DataAccessLayerPerson
{
public FirstName
{
get; set;
}
public MiddleName
{
get; set;
}
public LastName
{
get; set;
}
public getFullName()
{
return FirstName + MiddleName + LastName;
}
}
class BusinessLogicLayerPerson
{
public FirstName
{
get; set;
}
public MiddleName
{
get; set;
}
public LastName
{
get; set;
}
public FullName
{
get; set;
}
}
A similar common case, is when a table has a field conceptually used as boolean, but, programatically used as char(1) storing 'f' or 't', or as integer or as bit, and I have to use them in programming as boolean.
So, I use some logic in the data access layer, and read and write to those fields as booleans.
Cheers.
We had the same problem in our project, so we did as this:
#MappedSuperclass
public class UserDTO {
// this is the class which can be regenerated by code generator, and only contains database fields
}
#Entity
public class User extends UserDTO {
// this is the class containing more business methods, methods do things that are not part of the database columns
}