Using FluentValidation to create validation rule for more than one property - fluentvalidation

I am trying to implement a complex validation scenario in FluentValidation.
Let's say I have a Car class. It has four properties: Color, Make, Model, Year.
I want to construct a validation rule that involves three of these properties. For the sake of conversation, let's say I want a validation rule like the following:
if car.make = nissan and car.year = 2010 then
if car.color <> green then
throw a validation error since the system does not support 2010 nissans that are not green.
end
end
I know this is a silly example. I, however, have validation rules in my app that involve more than one aspect of my object. This is the heart of my question.
I have tried to follow the guidance from http://fluentvalidation.codeplex.com/wikipage?title=Custom on using "Using AbstractValidator.Custom" .
Does anyone have other working examples of the AbstractValidator.Custom working?
Thanks in advance for your time.

Below is a simple way of implementing validations involving multiple properties
public class CarValidator : AbstractValidator<Car>
{
public CarValidator()
{
RuleFor(c => c.Color).NotEqual("Green").When(MakeIsNisssanAndYearIs2000))
}
private bool MakeIsNisssanAndYearIs2000(Car arg)
{
return arg.Make == "Nissan" && arg.Year == 2000;
}
}
public class Car
{
public string Color { get; set; }
public string Make { get; set; }
public int Year { get; set; }
}
You can parameterise MakeIsNissanAndYearIs2000 method so that make and model are passed to the method as parameters. But this should give you an idea of how to implement validations involving multiple properties

Related

Should I have both text and value in my model for a property that is selected from dropdownlist

In ASP.NET MVC application I have a model named CarSearchCriteria:
public class CarSearchCriteria{
public int CarMake {get;set;} // This is selected from a dropdownlist
public int YearOfFirstReg {get;set;}
public string ModelVariant {get;set}
}
I have two views - one for editing and the other one for viewing. In the editing view for the CarMake property I can do the following. I know I could have used DropDownListFor but didn't want to mess with SelectList for the time being:
<select name="CarMake">
<option value="1">BMW</option>
<option value="2">Mercedes</option>
<option value="3">Toyota</option>
</select>
So the model binding mechanism will easily bind the selected value to the appropriate model property. But what about the reading mode. I can't show 1s or 2s. I need to show BMW, Mercedes and so on. My question is what is the preferred way, do I have to have a property name that holds the actual textual information, something like CarMakeText?
You could have both the identifier (which you currently have) as well as the Make object itself. The latter would never need to be accessed when building the model, but can be accessed when reading the model. A lazy-loaded read-only property often works well for that. Something like this:
public int CarMakeID { get; set; }
public Make CarMake
{
get
{
if (CarMakeID == default(int))
return null;
// fetch the Make from data and return it
}
}
Naturally, this depends a lot on what a Make actually is and where you get it. If there's just some in-memory list somewhere then that should work fine. If fetching an instance of a Make is a little more of an operation (say, fetching from a database) then maybe some in-object caching would be in order in case you need to access it more than once:
public int CarMakeID { get; set; }
private Make _carMake;
public Make CarMake
{
get
{
if (CarMakeID == default(int))
return null;
if (_carMake == null)
// fetch the Make from data and save it to _carMake
return _carMake;
}
}
David's solution is just fine but for some reason I find my own solution to better fit my needs and besides that I find it more elegant. So basically what I do is I create a class that holds the textual descriptions of all the properties that keep just ID. For example, I have the following model:
public class EmployeeModel{
public int EmployeeID {get;set;}
public string FullName {get;set}
*public int DepartmentID {get;set}
*public int SpecialityID {get;set;}
public int Age {get;set;}
}
The properties marked with asterisk are the properties that keep ids of possible many predefined options and when showing we're supposed to show the actual descriptions, not the number representations. So for this purpose, we create a separate class:
public class EmployeeTextValues{
public string DepartmentName {get;set;}
public string SpecialityName {get;set;}
}
And then I just add this class as a property to my model:
public EmployeeTextValues TextValues {get;set;}
After that, it's quite easy to access it from anywhere, including Razor.
P.S. I'm sure that a lot of people will tend to do the following before initializing this property:
Employee emp=new Employee;
emp.Age=25;
emp.TextValues.DepartmentName="Engineering";// Don't do this
If you try to access or set Textvalues.Someproperty you'll get Object reference not set to an instance of an object. So do not forget to set TextValues first to some initialized object. Just a kind reminder, that's all.

Change ViewModel default data strictly from server in MVC?

I know this is a weird one but bear with me. I need to set a default state/value for form inputs on a portion of my application.
In my "MainController" I pull up a portion (or 'wrapper' of sorts) page and then pull partial views from this main page. Here's a pseudo-code example:
User goes to Main ->
MainController/Index Called
-> User clicks Link A ->
AJAX .load() pulls html from PartialViewA into #partialContainer
-> User clicks Link B ->
AJAX .load pulls html from PartialViewB into #partialContainer
Here's the AJAX call:
$("#mainPanel").load('#Url.Action("GetModule","Settings")' + '?partialName=' + moduleName);
...and the corresponding server-side action that handles it:
public ActionResult GetModule(string partialName)
{
return PartialView(partialName);
}
It works great for me, each of the modules has plenty of form fields on them, all interacting well with one another and server so that isn't my problem. The issue is setting default values from the dbase for the form fields contained in the partial views.
For instance the "General" partial has many checkboxes which will determine how portions of the application display. I want to pull from the database the pre-exisiting boolean value and when the partial gets pulled from GetModule(), have these values defaulted.
I've taken a look around and I'm afraid the way that I am pulling the partial's into the main page may be the issue. I thought I could build the defaults into the constructor like so:
public class GeneralViewModel
{
public GeneralViewModel()
{
var Data = from m in dataContext.Table
where m.UserID == _id
select new
{
m.Data1,
m.Data2,
};
foreach(var setting in Data)
{
Checkbox1 = Convert.ToBoolean(setting.Data1); // Conversion from bool? to bool
Checkbox2 = Convert.ToBoolean(setting.Data2); // Conversion from bool? to bool
}
}
public bool Checkbox1 { get; set; }
public bool Checkbox2 { get; set; }
}
But it would appear the constructor never gets called. That sort of makes sense, except when you consider the fact that my form fields are not only rendering properly, but communicating with the database just fine as well. So the question is, what am I doing wrong? Is it the way I call the Partial's or am I missing something with assigning values to my VM values?
As always, thanks SO!
I think it's better to have different action methods for rendering the partial views, but for your case, i think this solution would work.
Have a Model that contains the other view models
public class ViewModel
{
public ViewModel1 ViewModel1 { get;set;}
public GenereViewModel General {get;set;}
}
Then in your controller you could initialize the viewmodel based on the partial name.
public ActionResult GetModule(string partialName)
{
var model = new ViewModel();
switch (partialName)
{
case "General": model.General = InitializeGeneral();
break;
case "ViewModel1": model.ViewModel1 = InitializeViewModel1(); break;
}
return PartialView(partialName, model);
}
private GeneralViewModel InitializeGeneral()
{
// initalize then return model
}

WCF, Linq Error:cannot implicitly convert type System.linq.iorderedQueryable<> to System.Collection.Generic.List<>

I am getting an error : i am using entity framework, wcf.
Error:cannot implicitly convert type System.linq.iorderedQueryable<xDataModel.Info> to System.Collection.Generic.List<xServiceLibrary.Info>
Below are my code:
WCF Service:
namespace xServiceLibrary
{
public List<Info> GetScenario()
{
xEntities db = new xEntities();
var query = from qinfo in db.Infoes
select qinfo;
//return query.Cast<Info>().ToList(); (not working)
//return query.toList(); (not working)
return query;
}
}
Interface:
namespace xServiceLibrary
{
[OperationContract]
List<Info> GetScenario();
}
Class:
namespace xServiceLibrary
{
[DataContract]
public class Info
{
[DataMember]
public int Scenario_Id;
[DataMember]
public string Scenario_Name { get; set; }
[DataMember]
public string Company_Name { get; set; }
}
}
update:(2)
I have two class library files.
One is xDataModel namespace in which i have created xmodel.edmx file.
second is xServiceLibrary namespace where i am implementing Wcf Service.
i have attached the xDataModel.dll file in my xServiceLibrary so that i could query my EF Model.
i am not able to understand the concept. any help would be appreciated.
The problem is that you have two different types named Info: DataModel.Info and ServiceLibrary.Info - because these are different types you cannot cast one into the other.
If there is no strong reason for both being there I would eliminate one of them. Otherwise as a workaround you could project DataModel.Info to ServiceLibrary.Info by copying the relevant properties one by one:
var results = (from qinfo in db.Infoes
select new ServiceLibrary.Info()
{
Scenario_Id = qinfo.Scenario_Id,
//and so on
}).ToList();
The problem is that you have two different classes, both called Info, both in scope at the time you run your query. This is a very very bad thing, especially if you thought they were the same class.
If DataModel.Info and ServiceLibrary.Info are the same class, you need to figure out why they are both in scope at the same time and fix that.
If they are different classes, you need to be explicit about which one you are trying to return. Assuming that your EF model includes a set of DataModel.Info objects, your options there are:
Return a List<DataModel.Info> which you can get by calling query.ToList()
Return a List<ServiceLibrary.Info> which you can get by copying the fields from your DataModel.Info objects:
var query = from qinfo in db.Info
select new ServiceLibrary.Info
{
Scenario_Id = q.Scenario_Id,
Scenario_Name = q.Scenario_Name
Company_Name = q.Company_Name
};
Return something else, such as your custom DTO object, similar to #2 but with only the specific fields you need (e.g. if ServiceLibrary.Info is a heavy object you don't want to pass around.
In general, though, your problem is centered around the fact that the compiler is interpreting List<Info> as List<ServiceLibrary.Info> and you probably don't want it to.

NHibernate Criteria select items by the group by and sum of itemid within another table

public class SearchText
{
public virtual int Id { get; set; }
public virtual string Text { get; set; }
}
public class SearchTextLog
{
public virtual int Id { get; set; }
public virtual SearchText SearchText { get; set; }
public virtual User User { get; set; }
public virtual int SearchCount { get; set; }
public virtual DateTime LastSearchDate { get; set; }
}
I am trying to select the top 5 SearchText items based on the sum of their count within the SearchTextLog. Currently I have only been able to resolve this by first performing a query to get the top 5 items, and then using the result within a second query. I was wondering if someone could show me the light and teach me how I could integrate these two seperate queries into a single unit.
Here is what I have currently:
var topSearchCriteria = Session.CreateCriteria(typeof (SearchTextLog))
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("SearchText.Id"))
.Add(Projections.Alias(Projections.Sum("SearchCount"), "SearchCount")))
.AddOrder(Order.Desc("SearchCount"))
.SetMaxResults(topSearchLimit)
.List<int>();
return Session.CreateCriteria<SearchText>()
.Add(Restrictions.In("Id", topSearchCriteria.ToArray()))
.List<SearchText>();
Edit:
Oh no, I just realised my current solution will lose the important order by of the results. So I will definitely have to incorporate the queries. :-/
Edit:
I tried a bidirectional mapping too to allow the following statement, however, I can't get it to return SearchText items. It simply complains that the SearchText properties aren't in a grouping.
return Session.CreateCriteria<SearchText>()
.CreateAlias("SearchTextLogs", "stl")
.AddOrder(Order.Desc(Projections.Sum("stl.SearchCount")))
.SetMaxResults(topSearchLimit)
.SetResultTransformer(Transformers.AliasToEntityMap)
.List<SearchText>();
Excuse my ignorance, but Nhibernate is completely new to me, and requires a completely different way of thinking.
Ok, I think I have figured out a solution.
My original solution as per my question won't work because NHibernate doesn't yet support the ability to do a group by property without adding it to the select clause (see: link text).
While fooling around however, I came across these cool things called ResultTransformers. Using the AliasToBean result transformer Nhibernate will automatically map the alias's I give to each projection item to properties by the same name within a type I specify. I simply specified my SearchText object (however, I had to add an additional TotalSearchCount property for the sum projection item). It populated my objects perfectly and returned them.
return Session.CreateCriteria(typeof(SearchTextLog))
.CreateAlias("SearchText", "st")
.SetProjection(Projections.ProjectionList()
.Add(Projections.Alias(Projections.GroupProperty("st.Id"), "Id"))
.Add(Projections.Alias(Projections.GroupProperty("st.Text"), "Text"))
.Add(Projections.Alias(Projections.Sum("SearchCount"), "TotalSearchCount")))
.SetMaxResults(topSearchLimit)
.AddOrder(Order.Desc("TotalSearchCount"))
.SetResultTransformer(Transformers.AliasToBean(typeof(SearchText)))
.List<SearchText>();
I am surprised this wasn't easier to do. It's taken me about 4 to 5 hours of research and dev to figure this one out. Hopefully my NHibernate experience will get easier with more and more experience.
I hope this helps someone else out there!
doesn't this work?
var critterRes = Session.CreateCriteria(typeof (SearchTextLog))
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("SearchText"))
.Add(Projections.Property("SearchText"))
.Add(Projections.Alias(Projections.Sum("SearchCount"), "SearchCount")))
.AddOrder(Order.Desc("SearchCount"))
.SetMaxResults(topSearchLimit)
.List<SearchText>()

DDD confused with Repository Pattern and Reports

I am new to DDD and the Repository pattern, so my understanding of it might be totally wrong. But I am trying to learn it. Having said that I need to create an application, which shows the zones of a store. I create a ZoneRepository for that purpose, which works so far with my few methods. Now in that application I also need to show the distinct styles for that store. The list of styles will be used to drag them into the individual zones. Now my question is where does the styles class belong to, since its kind of a mini-report. Does that "StyleReport" belong into the repository? Does it belong somewhere else? How you know where it belongs to? Please help me to understand.
Repositories only act on Aggregate Roots. Aggregates are a boundary around one or more objects that are treated as a unit. By that I mean, when you operate on that data (inserting, updating, deleting, etc.), all of the objects within that boundary are affected accordingly. Every aggregate has a root. This root is what is referenced externally by other parts of the software. I guess one way to describe it is "something that doesn't rely on something else".
It's a little challenging to derive the proper definition of your domain from a description of your existing models. Furthermore, the design should be based on the business model and needs, not how your UI or application works. So, you should model it on the general problem you are solving, not on how you think you'd like to solve it.
It sounds like you have an entity Store. A Store can be divided up into one or more Zones. Each Zone then has one or more StyleReports. It sounds to me like the Zones are dependent on a Store, so the Store is the aggregate root. Now, perhaps these StyleReport entities are a global set of objects that you offer in your problem domain (meaning you define the StyleReports separately, application-wide, and refer to them in your Zones). In that case, perhaps StyleReport is also an aggregate root.
Here are some example models (C#, not sure what language you're using). However, don't take this as the absolute word. If I don't know the specifics about your domain, I can't very well model it.
public class Store
{
public Int32 ID { get; }
public String Name { get; set; }
public IList<Zone> Zones { get; private set; }
public Store()
{
Zones = new List<Zone>();
}
public void AddZone(Zone zone)
{
Zones.Add(zone);
}
}
public class Zone
{
public Int32 ID { get; }
public String Name { get; set; }
public IList<StyleReport> Styles { get; private set; }
public Zone()
{
Styles = new List<StyleReport>();
}
public void AddStyle(StyleReport style)
{
Styles.Add(style);
}
}
public class StoreRepository : Repository<Store>
{
public Store Get(Int32 id)
{
// get store from persistence layer
}
// find, delete, save, update, etc.
}
public class StyleReportRepository : Repository<StyleReport>
{
public StyleReport Get(Int32 id)
{
// get style from persistence layer
}
// find, delete, save, update, etc.
}
And so when modifying a store's zones and adding styles, maybe something like this
IRepository<Store> storeRepository = new StoreRepository();
IRepository<StyleReport> stylesRepository = new StyleReportRepository();
Store store = storeRepository.Get(storeID); // store id selected from UI or whatever
// add a zone to the store
Zone someZone = new Zone { Name = zoneNamea }; // zone name was entered by the UI
someZone.AddStyle(styleRepository.Get(styleID)); // style id was selected from UI
storeRepository.Update(store);