How to avoid repeated external calls in FluentValidation - c#

I'm writing validation for a class (e.g. Car) which requires a number of similar/identical database calls.
RuleFor(c => c.Id).MustAsync(async (car, id, context, cancellation) =>
{
return await _carRepository.Get(id) != null;
}).WithMessage("Car with id '{PropertyValue}' does not exist!");
RuleFor(c => c.Model).MustAsync(async (car, model, context, cancellation) =>
{
var expectedModel = (ModelType)context.ParentContext.RootContextdata["ExpectedModel"]
var databaseCar = await _carRepository.Get(car.Id); // Repeated database call
return databaseCar.Model == expectedModel;
}).WithMessage('Stored car does not have the expected model.');
Ideally I would do this call once but I gather storing the result as a member on the validator instance is not advised, and overriding ValidateAsync with the database result added to the context (similarly to ExpectedModel in the example above) results in rather clumsy code to retrieve it.
Am I missing something?

One quick solution could be to add some kind of memoization/caching on your Repository class, so that multiple requests for the same Car within the same context (e.g. HTTP Request) will remember and return the same object without requiring multiple round-trips. But there might be a better way.
There are various levels of validation to consider. As Jammer points out, FluentValidation is usually used to validate the consistency of a given model: did the client send me something that appears on the surface to be a valid request? Determining whether that request is valid given the current state of data is another level of validation that people often do in different ways.
One way that you could get the best of both worlds is to create a new class to represent both the given car model and everything that your application needs in order to validate it.
public class ValidCar
{
public CarModel Model {get; set;}
public CarEntity Entity {get; set;}
}
First you assemble all the data you need into a new ValidCar, and then you can use FluentValidation rules on this new model to ensure it's actually valid.
One benefit to this approach is you can have your business logic methods require a ValidCar as a parameter instead of just a CarModel. This makes it very difficult to accidentally forget to validate the car in some code path, and it prepackages up data that's likely to be useful to much of the business-level logic that you plan to use.

I would argue that checking for an existing item with the same ID is not a validation question.
If you have to do this. Create a method in your repository that specifically checks this in an optimised way. Only select the ID column so at least you aren't loading and materialsing the entire entity.

Related

Which class should be responsible for creating ID for entity?

I'm struggling a little bit with following problem. Let's say I want to manage dependencies in my project, so my domain won't depend on any external stuff - in this problem on repository. In this example let's say my domain is in project.Domain.
To do so I declared interface for my repository in project.Domain, which I implement in project.Infrastructure. Reading DDD Red Book by Vernon I noticed, that he suggests that method for creating new ID for aggregate should be placed in repository like:
public class EntityRepository
{
public EntityId NextIdentity()
{
// create new instance of EntityId
}
}
Inside this EntityId object would be GUID but I want to explicitly model my ID, so that's why I'm not using plain GUIDs. I also know I could skip this problem completely and generate GUID on the database side, but for sake of this argument let's assume that I really want to generate it inside my application.
Right now I'm just thinking - are there any specific reasons for this method to be placed inside repository like Vernon suggests or I could implement identity creation for example inside entity itself like
public class Entity
{
public static EntityId NextIdentity()
{
// create new instance of EntityId
}
}
You could place it in the repository as Vernon says, but another idea would be to place a factory inside the constructor of your base entity that creates the identifier. In this way you have identifiers before you even interact with repositories and you could define implementation per your ID generation strategy. Repository could include a connection to something, like a web service or a database which can be costly and unavailable.
There are good strategies (especially with GUID) that allow good handling of identifiers. This also makes your application fully independent of the outside world.
This also enables you to have different identifier types throughout your application if the need arises.
For eg.
public abstract class Entity<TKey>
{
public TKey Id { get; }
protected Entity() { }
protected Entity(IIdentityFactory<TKey> identityFactory)
{
if (identityFactory == null)
throw new ArgumentNullException(nameof(identityFactory));
Id = identityFactory.CreateIdentity();
}
}
Yes, you could bypass the call to the repository and just generate the identity on the Entity. The problem, however, is that you've broken the core idea behind the repository: keeping everything related to entity storage isolated from the entity itself.
I would say keep the NextIdentity method in the respository, and still use it, even if you are only generating the GUID's client-side. The benefit is that in some future where you want to change how the identity's are being seeded, you can support that through the repository. Whereas, if you go with the approach directly on the Entity, then you would have to refactor later to support such a change.
Also, consider scenarios where you would use different repositories in such cases like testing. ie. you might want to generate two identities with the same ID and perform clash testing or "does this fail properly". Having a repository handle the generation gives you opportunity to get creative in such ways, without making completely unique test cases that don't mimic what actual production calls would occur.
TLDR; Keep it in the repository, even if your identifier can be client-side generated.

Using AutoMapper to load entities from the database?

Most of what I've read (e.g. from the author) indicates that AutoMapper should be used to map an an entity to a DTO. It should not load anything from the database.
But what if I have this:
public class Customer {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
public class CustomerDto {
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<int> OrderIds { get; set; } // here is the problem
}
I need to map from DTO to entity (i.e. from CustomerDto to Customer), but first I must use that list of foreign keys to load corresponding entities from the database. AutoMapper can do that with a custom converter.
I agree that it doesn't feel right... but what are the alternatives? Sticking that logic into a controller, service, a repository, some manager class? All that seems to be pushing the logic somewhere else, in the same tier. And if I do that, I must also perform the mapping manually!
From a DDD perspective, the DTO should not be part of the domain. So AutoMapper is also not part of the domain, because it knows about that DTO. So AutoMapper is in the same tier as the controllers, services, etc.
So does it make sense to put the DTO-to-entity logic (which includes accessing the database, and possibly throwing exceptions) into an AutoMapper mapping?
EDIT
#ChrisSimon's great answer below explains from a DDD perspective why I shouldn't do this. From a non-DDD perspective, is there a compelling reason not to use AutoMapper to load from the db?
To start with, I'm going to summarise my understanding of Entities in DDD:
Entities can be created - often using a factory. This is the start of their life-cycle.
Entities can be mutated - have their state modified - by calling methods on the entity. This is how they progress through their lifecycle. By ensuring that the entity owns its own state, and can only have its state modified by calling its methods, the logic that controls the entity's state is all within the entity class, leading to cleaner separation of business logic and more maintainable systems.
Using Automapper to convert from a Dto to the entity means the entity is giving up ownership of its state. If the dto is in an invalid state and you map that directly onto the entity, the entity may end up in an invalid state - you have lost the value of making entities contain data + logic, which is the foundation of the DDD entity.
To make a suggestion as to how you should approach this, I'd ask - what is the operation you are trying to achieve? DDD encourages us not to think about CRUD operations, but to think about real business processes, and to model them on our entities. In this case it looks like you are linking Orders to the Customer entity.
In an Application Service I would have a method like:
void LinkOrdersToCustomer(CustomerDto dto)
{
using (var dbTxn = _txnFactory.NewTransaction())
{
var customer = _customerRepository.Get(dto.Id);
foreach (var orderId in dto.OrderIds)
{
var order = _orderRepository.Get(orderId);
customer.LinkToOrder(order);
}
dbTxn.Save();
}
}
Within the LinkToOrder method, I would have explicit logic that did things like:
Check that order is not null
Check that the customer's state permits adding the order (are they currently active? is their account closed? etc.)
Check that the order actually does belong to the customer (what would happen if the order referenced by orderId belonged to another customer?)
Ask the order (via a method on the order entity) if it is in a valid state to be added to a customer.
Only then would I add it to the Customers Order's collection.
This way, the application 'flow' and infrastructure management is contained within the application/services layer, but the true business logic is contained within the domain layer - within your entities.
If the above requirements are not relevant in your application, you may have other requirements. If not, then perhaps it is not necessary to go the route of DDD - while DDD has a lot to add, its overheads are generally only worth it in systems with lots of complex business logic.
This isn't related to the question you asked, but I'd also suggest you take a look at the modelling of Customer and Order. Are they both independent Aggregates? If so, modelling Customer as containing a collection of Order may lead to problems down the road - what happens when a customer has a million orders? Even if the collection is lazy loaded, you know at some point something will attempt to load it, and there goes your performance. There's some great reading about aggregate design here: http://dddcommunity.org/library/vernon_2011/ which recommends modelling references by Id rather than reference. In your case, you could have a collection of OrderIds, or possibly even a completely new entity to represent the link - CustomerOrderLink which would have two properties - CustomerId, and OrderId. Then none of your entities would have embedded collections.

Entity Framework classes vs. POCO

I have a general difference of opinion on an architectural design and even though stackoverflow should not be used to ask for opinions I would like to ask for pros and cons of both approaches that I will describe below:
Details:
- C# application
- SQL Server database
- Using Entity Framework
- And we need to decide what objects we are going to use to store our information and use all throughout the application
Scenario 1:
We will use the Entity Framework entities to pass all around through our application, for example the object should be used to store all information, we pass it around to the BL and eventually our WepApi will take this entity and return the value. No DTOs nor POCOs.
If the database schema changes, we update the entity and modify in all classes where it is used.
Scenario 2:
We create an intermediate class - call it a DTO or call it a POCO - to hold all information that is required by the application. There is an intermediate step of taking the information stored in the entity and populated into the POCO but we keep all EF code within the data access and not across all layers.
What are the pros and cons of each one?
I would use intermediate classes, i.e. POCO instead of EF entities.
The only advantage I see to directly use EF entities is that it's less code to write...
Advantages to use POCO instead:
You only expose the data your application actually needs
Basically, say you have some GetUsers business method. If you just want the list of users to populate a grid (i.e. you need their ID, name, first name for example), you could just write something like that:
public IEnumerable<SimpleUser> GetUsers()
{
return this.DbContext
.Users
.Select(z => new SimpleUser
{
ID = z.ID,
Name = z.Name,
FirstName = z.FirstName
})
.ToList();
}
It is crystal clear what your method actually returns.
Now imagine instead, it returned a full User entity with all the navigation properties and internal stuff you do not want to expose (such as the Password field)...
It really simplify the job of the person that consumes your services
It's even more obvious for Create like business methods. You certainly don't want to use a User entity as parameter, it would be awfully complicated for the consumers of your service to know what properties are actually required...
Imagine the following entity:
public class User
{
public long ID { get; set; }
public string Name { get; set; }
public string FirstName { get; set; }
public string Password { get; set; }
public bool IsDeleted { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
public virtual ICollection<UserEvent> Events { get; set; }
}
Which properties are required for you to consume the void Create(User entity); method?
ID: dunno, maybe it's generated maybe it's not
Name/FirstName: well those should be set
Password: is that a plain-text password, an hashed version? what is it?
IsDeleted/IsActive: should I activate the user myself? Is is done by the business method?
Profiles: hum... how do I affect a profile to a user?
Events: the hell is that??
It forces you to not use lazy loading
Yes, I hate this feature for multiple reasons. Some of them are:
extremely hard to use efficiently. I've seen too much times code that produces thousands of SQL request because the developers didn't know how to properly use lazy loading
extremely hard to manage exceptions. By allowing SQL requests to be executed at any time (i.e. when you lazy load), you delegate the role of managing database exceptions to the upper layer, i.e. the business layer or even the application. A bad habit.
Using POCO forces you to eager-load your entities, much better IMO.
About AutoMapper
AutoMapper is a tool that allows you to automagically convert Entities to POCOs and vice et versa. I do not like it either. See https://stackoverflow.com/a/32459232/870604
I have a counter-question: Why not both?
Consider any arbitrary MVC application. In the model and controller layer you'll generally want to use the EF objects. If you defined them using Code First, you've essentially defined how they are used in your application first and then designed your persistence layer to accurately save the changes you need in your application.
Now consider serving these objects to the View layer. The views may or may not reflect your objects, or an aggregation of your working objects. This often leads to POCOS/DTO's that captures whatever is needed in the view. Another scenario is when you want to publish objects in a web service. Many frameworks provide easy serialization on poco classes in which case you typically either need to 1) annotate your EF classes or 2) make DTO's.
Also be aware that any lazy loading you may have on your EF classes is lost when you use POCOS or if you close your context.

Where should I validate adding to my entity's collection property?

I'm just about to start a new pet project and I've been wondering about how I should go about validation when adding an entity to a parent's one-to-many collection. I'll use two example classes to summarize what I'm going on about a Student and a Teacher. Constraint here is that at any given time a Student can only be taught by one (and only one) Teacher who in-turn could be teaching one or more Students).
public class Student
{
public bool IsEnrolled { get; set; }
public virtual Teacher IsCurrentlyBeingTaughtBy { get; set; }
}
public class Teacher
{
public virtual ICollection<Student> IsCurrentlyTeaching { get; set; }
}
When students arrive at a class I need to assign them to the Teacher's IsCurrentlyTeaching collection, but I first need to make sure they're enrolled. My question is where best to validate this basic rule? The options going around my head currently are:
1. Use a repository pattern
As I'm going to be applying unit tests I'm leaning in favor of this method as I can wrap my data access logic up into a mockable object and there is a single responsibility here so I only have to validate this in my repository once. BUT - is validation the responsibility of the repository, or should I be only dealing with the CRUD of entities in a repository?
2. Validate this in the controller action
I should mention here that I propose this to be an MVC3 project, so keeping specifically to that should I be performing this validation in the controller's action before adding the Student to the repository (and subsequently the Teacher's list of students they're currently teaching). BUT - am I heading down a fat controller path that I really shouldn't be?
3. Perform this validation on the Teacher entity
Cutting out the middle-man (i.e. repository) should I be adding the Student via a method on the Teacher POCO such as AddStudent(Student student) and throwing a custom exception when trying to add a student who hasn't been enrolled?
There are probably more options available, but these are the three I'm trying to choose between at this present moment and I've got a little tunnel vision from thinking about this. Obviously all of the above can be suitably unit tested but thinking long-term (and accommodating growth) which path should I be heading down?
You may be able to create your own custom validator for this. That would let you piggyback on the validation the MVC is already providing. I've never tried this, but I would imagine something like this would work:
public class EnsureEnrollment : ValidationAttribute
{
public EnsureEnrollment () { }
public override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var studentList = value as IEnumerable<Student>;
if (studentList == null)
{
return ValidationResult.Success;
}
foreach(Student s in studentList )
{
if(!s.IsEnrolled)
{
//Insert whatever error message you want here.
return new ValidationResult("Student \"" + s.Name + "\" is not enrolled.");
}
}
return ValidationResult.Success;
}
}
Then on your property just add your annotation:
[EnsureEnrollment()]
public virtual ICollection<Student> IsCurrentlyTeaching { get; set; }
Personally, I like having my validation as part of static CRUDL methods on my entities. True, you have to pass the context in to every one of them, but it keeps the controllers a lot cleaner and makes all of that functionality readily available for any other projects that may use your entities in the future.
Previously I created a base class that all of my entities derived from which had a must override for Validate. The Validate method was called by almost all of the CRUDL methods and other working methods to ensure that the entity was proper before acting on it. Most of these validation rules were a bit more complex that could be easily expressed using the DataAnnotations attributes.
Or you can integrate specific validation points into a method with a more specific purpose. Take for instance:
public static bool AddToTeacher(SchoolContext db, Student student, Teacher teacher)
{
if (student.IsEnrolled)
{
teacher.IsCurrentlyTeaching(student);
return db.SaveChanges() > 0;
}
return false;
}
The AddToTeacher method only ensures that a specific requirement is met. If I wanted to ensure that the student was properly formed and was of eligible course track and what not, I would likely write a short method (or several all called by a "container" method) to validate those particular points.
In short, I do my best to keep every bit of entity specific code on the entity so that the controller is mostly ignorant of how the entities work.
As for on which entity to put it, it depends on how you think. Student.AddToTeacher is just as viable in my opinion as Teacher.AddStudent. I personally would use the former just because that is what most of my entities currently look like with "child" entities adding themselves to "parents" rather than the other way around.

Send domain entity as paremeter or send entity id as parameter in application services

when using domain driven design, is it better that your services' methods receive an entity as parameter or the id of your entity as parameter so that you can retrieve the entity inside the method using a repository?
for example:
public void Apply(Job job, User user)
versus
public void Apply(int jobId, int userId)
DDD is about mapping your client's vocabulary to your design. Your client (hopefully) talks about users applying for jobs, not some integer ID being linked to another integer ID. Try to stick to the real world as close as possible, unless it becomes a burden.
By passing in the entire entity, you can benefit from the entity's behavior immediately, without having to construct it first.
So stick to entities, unless you have a situation where you often only have an ID to work with. This usually happens when you're dealing with external systems, such as web services. In that case you can create a method overload that accepts the ID. This overload should validate the ID, construct the entity and call the overload that accepts the entity.
public void Apply(int jobId, int userId)
{
// Validate the IDs.
// Construct the entities.
var job = ...;
var user = ...;
// Call the 'proper' overload.
Apply(job, user);
}
public void Apply(Job job, User user)
{
// Actual business logic belongs here.
}
Again: try to avoid such overloads as much as possible, unless you're dealing with external systems that only return the ID.
From a coding point of view, entities are also better than integers. An integer can be of any integer value, so you'd have to validate it everywhere you use it. Your factories are responsible for constructing valid entities and your (domain) logic should keep your entities in a valid state. So using the entity is completely safe and shouldn't require much validation.
It depends on where your Application Service resides:
If your Service executes within the same AppDomain (i.e. you're calling it from the same executable), then passing the object is ideal. The Service can easily access other objects within the object graph.
If your Service executes in a different AppDomain (e.g. behind a WebService or other remote location), you should use an ID. The Service would then load the appropriate object from the persistence store before working with it.
If you try to send objects down the wire, you likely run into the problems described here.
Hope that helps.
If you send the object, you are creating dependency between the service and the entity. One of the advantages of using services is to act as facades to reduce dependency graph between classes and reduce the complexity of the design. It's better to use primitive types, structs, enums in service contracts but when dealing with large number of method parameters you may encapsulate them in an object but in this case it will be a DTO not an entity.
I use ViewModel for passing "flat entities" to/from application service. Also I use Document Message pattern to communicate with application service. In application service a use extension methods for business entities something like this:
public BusinessEntityViewModel ConvertToViewModel(this BusinessEntity businessEntity)
{
BusinessEntityViewModel bevm = new BusinessEntityViewModel{ Id = businessEntity.Id, ...}
return bevm;
}
In my understanding, difference is only the fact what does Domain do with User and Job to make "Apply" operation. If ID is quite enough, then it is ok to leave there only ID.

Categories