What is the correct way to do Business Validation on entities?
-
Hi, What is the correct way to do Business Validation on entities with Entity Framework 6. By business Validation I mean validation that require more than one entity in process with, sometime, a little more complex rules that involve all these entities. A validation that require the system to call he database. I already checked this post: [ScottGu's Blog - Class-Level Model Validation with EF Code First and ASP.NET MVC 3](https://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3) But, like most example about EF and validation all validations are limited to simple check that consider only the current entity. I need to do some check based on other entities. Example: I have a
order
entity that contain a quantity of product but this quantity must be a multiple of a variable stored in myitem
entity. This is what I call the business validation. To perform this validation on order I need to go in database and check the item selected for this order.public class Order : IValidateObject { public int Id { get; set; } public int ItemId { get; set; } public int Quantity { get; set; } public IEnumerable Validate(ValidationContext validationContext) { var item = DbContext.Items.Find(ItemId); // <-- What about this? if (Quantity % item.Multiple != 0) yield return new ValidationResult("Quantity not multiple of item", new\[\] {Quantity}); } } public class Item { public int Id { get; set; } public int Multiple { get; set; } }
How should I implement this kind of business validation that require other entities? I'm more looking for a good tutorial about this subject. I search but each time I think I find the subject the tutorial is limited to classic validation with Data Annotation or other type of classic validation. Maybe you will juste tell me there is no problem to class my context in the Validate method. It is just that most of tutorial separate the entity layer from the context layer suggesting entities must only be simple POCO with no behavior. I most and most disagree with this but I feel alone.
-
Hi, What is the correct way to do Business Validation on entities with Entity Framework 6. By business Validation I mean validation that require more than one entity in process with, sometime, a little more complex rules that involve all these entities. A validation that require the system to call he database. I already checked this post: [ScottGu's Blog - Class-Level Model Validation with EF Code First and ASP.NET MVC 3](https://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3) But, like most example about EF and validation all validations are limited to simple check that consider only the current entity. I need to do some check based on other entities. Example: I have a
order
entity that contain a quantity of product but this quantity must be a multiple of a variable stored in myitem
entity. This is what I call the business validation. To perform this validation on order I need to go in database and check the item selected for this order.public class Order : IValidateObject { public int Id { get; set; } public int ItemId { get; set; } public int Quantity { get; set; } public IEnumerable Validate(ValidationContext validationContext) { var item = DbContext.Items.Find(ItemId); // <-- What about this? if (Quantity % item.Multiple != 0) yield return new ValidationResult("Quantity not multiple of item", new\[\] {Quantity}); } } public class Item { public int Id { get; set; } public int Multiple { get; set; } }
How should I implement this kind of business validation that require other entities? I'm more looking for a good tutorial about this subject. I search but each time I think I find the subject the tutorial is limited to classic validation with Data Annotation or other type of classic validation. Maybe you will juste tell me there is no problem to class my context in the Validate method. It is just that most of tutorial separate the entity layer from the context layer suggesting entities must only be simple POCO with no behavior. I most and most disagree with this but I feel alone.
The "Enumerable" makes no sense. "Validation" is an all or nothing proposition. If you want to return multiple error / messages, return a list. If the list is "empty", you might consider things valid and then do a "save". Other than that, you've provide no information about the environment: online, batch, whatever.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
-
The "Enumerable" makes no sense. "Validation" is an all or nothing proposition. If you want to return multiple error / messages, return a list. If the list is "empty", you might consider things valid and then do a "save". Other than that, you've provide no information about the environment: online, batch, whatever.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
The
IEnumerable<ValidationResult>
is just how theIValidatableObject
interface works: IValidatableObject.Validate(ValidationContext) Method (System.ComponentModel.DataAnnotations) | Microsoft Docs[^] It works that way because each validation error can be associated with one or more properties of the object being validated, and some UI frameworks will use that to display the error next to the relevant control.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Hi, What is the correct way to do Business Validation on entities with Entity Framework 6. By business Validation I mean validation that require more than one entity in process with, sometime, a little more complex rules that involve all these entities. A validation that require the system to call he database. I already checked this post: [ScottGu's Blog - Class-Level Model Validation with EF Code First and ASP.NET MVC 3](https://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3) But, like most example about EF and validation all validations are limited to simple check that consider only the current entity. I need to do some check based on other entities. Example: I have a
order
entity that contain a quantity of product but this quantity must be a multiple of a variable stored in myitem
entity. This is what I call the business validation. To perform this validation on order I need to go in database and check the item selected for this order.public class Order : IValidateObject { public int Id { get; set; } public int ItemId { get; set; } public int Quantity { get; set; } public IEnumerable Validate(ValidationContext validationContext) { var item = DbContext.Items.Find(ItemId); // <-- What about this? if (Quantity % item.Multiple != 0) yield return new ValidationResult("Quantity not multiple of item", new\[\] {Quantity}); } } public class Item { public int Id { get; set; } public int Multiple { get; set; } }
How should I implement this kind of business validation that require other entities? I'm more looking for a good tutorial about this subject. I search but each time I think I find the subject the tutorial is limited to classic validation with Data Annotation or other type of classic validation. Maybe you will juste tell me there is no problem to class my context in the Validate method. It is just that most of tutorial separate the entity layer from the context layer suggesting entities must only be simple POCO with no behavior. I most and most disagree with this but I feel alone.
In this case, you could probably implement the validation by adding a navigation property:
public class Order : IValidateObject
{
public int Id { get; set; }
public int ItemId { get; set; }
public int Quantity { get; set; }public virtual Item Item { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (Quantity % Item.Multiple != 0) { yield return new ValidationResult("Quantity not multiple of item", new\[\] { Quantity }); } }
}
However, you'd need to test to make sure the property was always set. Alternatively, you could override the
ValidateEntity
method on yourDbContext
: DbContext.ValidateEntity(DbEntityEntry, IDictionary<Object,Object>) Method (System.Data.Entity) | Microsoft Docs[^] NB: This wouldn't work with EF Core - it no longer tries to validate the entities before saving them. If you wanted to validate the entities before trying to save them, you would have to write your own validation logic - for example: Improving Model Validation for Entity Framework Core 2.0 | Ballard Software[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
The
IEnumerable<ValidationResult>
is just how theIValidatableObject
interface works: IValidatableObject.Validate(ValidationContext) Method (System.ComponentModel.DataAnnotations) | Microsoft Docs[^] It works that way because each validation error can be associated with one or more properties of the object being validated, and some UI frameworks will use that to display the error next to the relevant control.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
So, instead of "one" call, he does multiple calls to get all the errors "because there may be multiple properties". Sorry, I fail to see the connection. The interface is at the "class level", not the property level.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
-
So, instead of "one" call, he does multiple calls to get all the errors "because there may be multiple properties". Sorry, I fail to see the connection. The interface is at the "class level", not the property level.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
No, there's one call to get the list of validation errors. Each error can be associated with one or more properties, by specifying the member names in the
ValidationResult
. The interface is designed for validation rules on a class which need access to other properties of the class. Validation attributes on a property only get access to that property's value. That's fine for simple validation rules like "required" or "greater than zero", but it doesn't work for things like "confirm password must be equal to password".
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
No, there's one call to get the list of validation errors. Each error can be associated with one or more properties, by specifying the member names in the
ValidationResult
. The interface is designed for validation rules on a class which need access to other properties of the class. Validation attributes on a property only get access to that property's value. That's fine for simple validation rules like "required" or "greater than zero", but it doesn't work for things like "confirm password must be equal to password".
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Still doesn't answer why an enumerable is "better" than a list in this case. All you're doing is trading a yield for an Add (and making it more complicated for some … as indicated by OP's post).
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
-
Still doesn't answer why an enumerable is "better" than a list in this case. All you're doing is trading a yield for an Add (and making it more complicated for some … as indicated by OP's post).
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
The interface defines the method as returning
IEnumerable<ValidationResult>
. If you wanted to return aList<ValidationResult>
instead of using an iterator method, you could certainly do that. But I don't see how it would make things significantly simpler.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Still doesn't answer why an enumerable is "better" than a list in this case. All you're doing is trading a yield for an Add (and making it more complicated for some … as indicated by OP's post).
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
Gerry Schmitz wrote:
Still doesn't answer why an enumerable is "better" than a list in this case.
No one ever said it is "better". This is just how the interface is built. Implementers are free to return whatever they want, provided it implements
IEnumerable
."Five fruits and vegetables a day? What a joke! Personally, after the third watermelon, I'm full."
-
Gerry Schmitz wrote:
Still doesn't answer why an enumerable is "better" than a list in this case.
No one ever said it is "better". This is just how the interface is built. Implementers are free to return whatever they want, provided it implements
IEnumerable
."Five fruits and vegetables a day? What a joke! Personally, after the third watermelon, I'm full."