FluentValidation - Validate interfaced child properties - fluentvalidation

I'm trying to apply FluentValidation (v 9.1.1) on a tree structure, using the visitor pattern. The special thing about it is, that a couple of different tree elements all implement an interface and the child properties of the elements are of this interface type. In other words, the child properties are not strongly typed. Simplified model see below. Each validator goes on the specific implementation and I don't get the point, how to attach child validators for interface children.
Here is a demo model (working code):
public interface IElement
{
Type ResultType { get; }
TResult Accept<TResult>(IElementVisitor<TResult> visitor);
}
public class ConstElement : IElement
{
public object Value { get; set; }
public Type ResultType => Value?.GetType();
public TResult Accept<TResult>(IElementVisitor<TResult> visitor)
{
return visitor.VisitElement(this);
}
}
public class BinaryElement : IElement
{
// Child properties are not strongly typed.
public IElement Left { get; set; }
public IElement Right { get; set; }
public Operand Operand { get; set; }
public Type ResultType => Operand switch
{
Operand.Equal => typeof(bool),
Operand.GreaterThan => typeof(bool),
Operand.Plus => Left.GetType(),
Operand.Multiply => Left.GetType(),
_ => throw new NotImplementedException(),
};
public TResult Accept<TResult>(IElementVisitor<TResult> visitor)
{
return visitor.VisitElement(this);
}
}
public enum Operand { Equal, GreaterThan, Plus, Multiply }
public class ConstElementValidator : AbstractValidator<ConstElement>
{
public ConstElementValidator()
{
RuleFor(ele => ele.Value).NotNull().Must(value => (value is double) || (value is TimeSpan));
}
}
public class BinaryElementValidator : AbstractValidator<BinaryElement>
{
public BinaryElementValidator()
{
// Rules for the element itself
RuleFor(ele => ele.Left).NotNull();
RuleFor(ele => ele.Right).NotNull();
RuleFor(ele => ele).Must(ele => IsValidResultTypeCombination(ele.Left.ResultType, ele.Right.ResultType, ele.Operand));
// Add rules for child elements here? How?
}
private bool IsValidResultTypeCombination(Type left, Type right, Operand operand)
{
if (left == typeof(bool) && right != typeof(bool))
return false;
// other result type validations...
return true;
}
}
public interface IElementVisitor<TResult>
{
TResult VisitElement(ConstElement element);
TResult VisitElement(BinaryElement element);
}
public class ValidationVisitor : IElementVisitor<ValidationResult>
{
public ValidationResult VisitElement(ConstElement element)
{
return new ConstElementValidator().Validate(element);
}
public ValidationResult VisitElement(BinaryElement element)
{
// How to add validation of element.Left and element.Right,
// taking into account, that their type is IElement, while Validators are bound to the implementation type?
var result = new BinaryElementValidator().Validate(element);
var leftResult = element.Left.Accept(this);
var rightResult = element.Right.Accept(this);
// merge leftResult and rightResult with result
return result;
}
}
In general, there are two ways to add child validation. Either calling child validators directly in the validators, which would make the ValidationVisitor obsolete, or let focus the validators on their own logic and adding child validation in the ValidationVisitor, as shown in the code.
The only way I am able to proceed right now is by using the visitor and merging the validation results of an element and its child elements.
Is there a way to add child validators to the BinaryElement in this scenario? Either in the visitor or in the BinaryElementValidator directly.

There's a couple of different ways to do this. You can either define multiple rules for each of the interface implementors, or you can use a custom property validator to do runtime inspection on the type. This is similar to this answer.
Option 1: Multiple rule definitions with a type filter
With this option, you create a specific rule definition for each potential implementor of the interface:
// Inside your BinaryElementValidator use a safe cast inside the RuleFor definition.
// If it isn't the right type, the child validator won't be executed
// as child validators aren't run for null properties.
RuleFor(x => x.Left as BinaryElement).SetValidator(new BinaryElementValidator());
RuleFor(x => x.Left as ConstElement).SetValidator(new ConstElementValidator());
RuleFor(x => x.Right as BinaryElement).SetValidator(new BinaryElementValidator());
RuleFor(x => x.Right as ConstElement).SetValidator(new ConstElementValidator());
This is the simplest approach, but by having a more complex expression within the call to RuleFor you will be bypassing FluentValidation's expression cache, which will be a performance hit if you're instantiating the validator many times. I'll leave it for you to decide if that would be an issue in your application.
You may need to call OverridePropertyName for each rule too, as FluentValidation won't be able to infer the name of the property with this approach.
Option 2: A custom property validator
A slightly more complex solution, but means you can stick with simple property expressions inside RuleFor, meaning you won't bypass the cache. This makes use of a custom validator called PolymorphicValidator, which will inspect the type of the property at runtime.
RuleFor(x => x.Left).SetValidator(new PolymorphicValidator<BinaryElement, IElement>()
.Add<BinaryElement>(new BinaryElementValidator())
.Add<ConstElement>(new ConstElementValidator())
);
RuleFor(x => x.Right).SetValidator(new PolymorphicValidator<BinaryElement, IElement>()
.Add<BinaryElement>(new BinaryElementValidator())
.Add<ConstElement(new ConstElementValidator())
);
And here's the code for the PolymorphicValidator:
public class PolymorphicValidator<T, TInterface> : ChildValidatorAdaptor<T, TInterface> {
readonly Dictionary<Type, IValidator> _derivedValidators = new Dictionary<Type, IValidator>();
// Need the base constructor call, even though we're just passing null.
public PolymorphicValidator() : base((IValidator<TInterface>)null, typeof(IValidator<TInterface>)) {
}
public PolymorphicValidator<T, TInterface> Add<TDerived>(IValidator<TDerived> derivedValidator) where TDerived : TInterface {
_derivedValidators[typeof(TDerived)] = derivedValidator;
return this;
}
public override IValidator<TInterface> GetValidator(PropertyValidatorContext context) {
// bail out if the current item is null
if (context.PropertyValue == null) return null;
if (_derivedValidators.TryGetValue(context.PropertyValue.GetType(), out var derivedValidator)) {
return new ValidatorWrapper(derivedValidator);
}
return null;
}
private class ValidatorWrapper : AbstractValidator<TInterface> {
private IValidator _innerValidator;
public ValidatorWrapper(IValidator innerValidator) {
_innerValidator = innerValidator;
}
public override ValidationResult Validate(ValidationContext<TInterface> context) {
return _innerValidator.Validate(context);
}
public override Task<ValidationResult> ValidateAsync(ValidationContext<TInterface> context, CancellationToken cancellation = new CancellationToken()) {
return _innerValidator.ValidateAsync(context, cancellation);
}
public override IValidatorDescriptor CreateDescriptor() {
return _innerValidator.CreateDescriptor();
}
}
}
This approach is actually going to be added to the library in a future version - you can track its development here if you're interested: https://github.com/FluentValidation/FluentValidation/issues/1237

Related

how to make a custom error message with extension method in fluent validation

public class Validator : AbstractValidator<Command>
{
public Validator(ICheckExists<ICheckEntityExists> checkEntityExists)
{
RuleFor(x => x)
.EntityDoesNotExist(checkEntityExists, c => new CheckEntityExists()
{
TypeId = c.Id,
StatusId = c.StatusId
});
}
Hi, I Have a problem. The code above generates "must not exist" error message.
EntityDoesNotExist is an extension method that I can not change.Since it is an extension method I could not use any of this OverridePropertyName WithName WithMessage.
The question is how can I change the error message to a custom one.
I have written this code which does the thing
ValidatorOptions.Global.DisplayNameResolver = (type, member, expression) =>
{
if (member == null)
{
return "Hello world";
}
return member.Name;
};
But it works only if I have 1 rule that has no name and it looks not pretty.
Maybe there it is another way of achieving the same result?
The problem is that extension method you are using return an instance of IRuleBuilder<T, out TProperty> interface which doesn't contain definitions for method like WithMessage. This and other methods you mentioned are extension methods for IRuleBuilderOptions<T, TProperty> interface which inherits IRuleBuilder<T, out TProperty>.
So one of possible solutions is to wrap EntityDoesNotExist extension method into another method which will downcast the returned type to IRuleBuilderOptions<T, TProperty>
For example we have class called Person:
public class Person
{
public string Name { get; set; } = null!;
}
Extension method for Name property which returns IRuleBuilder type:
public static IRuleBuilder<T, string> ValidateNameLength<T>(this IRuleBuilder<T, string> ruleBuilder)
{
return ruleBuilder.Must(name => name.Length < 5).WithMessage("Incorrect length");
}
So we can wrap this method something like this:
public static IRuleBuilderOptions<T, string> ValidateNameLengthWrapper<T>(this IRuleBuilder<T, string> ruleBuilder)
{
return (IRuleBuilderOptions<T, string>) ruleBuilder.ValidateNameLength();
}
Then we can use WithMessage method to override error description:
public class Validator : AbstractValidator<Person>
{
public Validator()
{
CascadeMode = CascadeMode.Continue;
RuleFor(x => x.Name!).ValidateNameLengthWrapper().WithMessage("Name must be less than 5 characters");
}
}
But maybe would be better to write your own extension method or resolve the problem outside the validation context.

Json Serialize an interface's properties which have non primitive types [duplicate]

With a simple class/interface like this
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
How can I get the JSON string with only the "Name" property (only the properties of the underlying interface) ?
Actually, when i make that :
var serialized = JsonConvert.SerializeObject((IThing)theObjToSerialize, Formatting.Indented);
Console.WriteLine(serialized);
I get the full object as JSON (Id + Name);
The method I use,
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type _InterfaceType;
public InterfaceContractResolver (Type InterfaceType)
{
_InterfaceType = InterfaceType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties = base.CreateProperties(_InterfaceType, memberSerialization);
return properties;
}
}
// To serialize do this:
var settings = new JsonSerializerSettings() {
ContractResolver = new InterfaceContractResolver (typeof(IThing))
};
string json = JsonConvert.SerializeObject(theObjToSerialize, settings);
Improved version with nested interfaces + support for xsd.exe objects
Yet another variation here. The code came from http://www.tomdupont.net/2015/09/how-to-only-serialize-interface.html with the following improvements over other answers here
Handles hierarchy, so if you have an Interface2[] within an Interface1 then it will get serialized.
I was trying to serialize a WCF proxy object and the resultant JSON came up as {}. Turned out all properties were set to Ignore=true so I had to add a loop to set them all to not being ignored.
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type[] _interfaceTypes;
private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;
public InterfaceContractResolver(params Type[] interfaceTypes)
{
_interfaceTypes = interfaceTypes;
_typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
}
protected override IList<JsonProperty> CreateProperties(
Type type,
MemberSerialization memberSerialization)
{
var typeToSerialize = _typeToSerializeMap.GetOrAdd(
type,
t => _interfaceTypes.FirstOrDefault(
it => it.IsAssignableFrom(t)) ?? t);
var props = base.CreateProperties(typeToSerialize, memberSerialization);
// mark all props as not ignored
foreach (var prop in props)
{
prop.Ignored = false;
}
return props;
}
}
Inspired by #user3161686, here's a small modification to InterfaceContractResolver:
public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
return properties;
}
}
You can use conditional serialization. Take a look at this link. Basicly, you need to implement the IContractResolver interface, overload the ShouldSerialize method and pass your resolver to the constructor of the Json Serializer.
An alternative to [JsonIgnore] are the [DataContract] and [DataMember] attributes. If you class is tagged with [DataContract] the serializer will only process properties tagged with the [DataMember] attribute (JsonIgnore is an "opt-out" model while DataContract is "op-in").
[DataContract]
public class Thing : IThing
{
[DataMember]
public int Id { get; set; }
public string Name { get; set; }
}
The limitation of both approaches is that they must be implemented in the class, you cannot add them to the interface definition.
You can add the [JsonIgnore] annotation to ignore an attribute.
I'd like to share what we ended up doing when confronted with this task. Given the OP's interface and class...
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
...we created a class that is the direct implementation of the interface...
public class DirectThing : IThing
{
public string Name { get; set; }
}
Then simply serialized our Thing instance, deserialized it as a DirectThing, then Serialized it as a DirectThing:
var thing = new Thing();
JsonConvert.SerializeObject(
JsonConvert.DeserializeObject<DirectThing>(JsonConvert.SerializeObject(thing)));
This approach can work with a long interface inheritance chain...you just need to make a direct class (DirectThing in this example) at the level of interest. No need to worry about reflection or attributes.
From a maintenance perspective, the DirectThing class is easy to maintain if you add members to IThing because the compiler will give errors if you haven't also put them in DirectThing. However, if you remove a member X from IThing and put it in Thing instead, then you'll have to remember to remove it from DirectThing or else X would be in the end result.
From a performance perspective there are three (de)serialization operations happening here instead of one, so depending on your situation you might like to evaluate the performance difference of reflector/attribute-based solutions versus this solution. In my case I was just doing this on a small scale, so I wasn't concerned about potential losses of some micro/milliseconds.
Hope that helps someone!
in addition to the answer given by #monrow you can use the default [DataContract] and [DataMember]
have a look at this
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx
Finally I got when it will not work...
If you want to have inside another complex object it will not be properly serialized.
So I have made version which will extract only data stored in specific assembly and for types which have the same base interface.
So it is made as .Net Core JsonContractResolver.
In addition to data extraction it solves:
a) camelCase conversion before sending data to client
b) uses top most interface from allowed scope (by assembly)
c) fixes order of fields: field from most base class will be listed first and nested object will meet this rule as well.
public class OutputJsonResolver : DefaultContractResolver
{
#region Static Members
private static readonly object syncTargets = new object();
private static readonly Dictionary<Type, IList<JsonProperty>> Targets = new Dictionary<Type, IList<JsonProperty>>();
private static readonly Assembly CommonAssembly = typeof(ICommon).Assembly;
#endregion
#region Override Members
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
if (type.Assembly != OutputJsonResolver.CommonAssembly)
return base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties;
if (OutputJsonResolver.Targets.TryGetValue(type, out properties) == false)
{
lock (OutputJsonResolver.syncTargets)
{
if (OutputJsonResolver.Targets.ContainsKey(type) == false)
{
properties = this.CreateCustomProperties(type, memberSerialization);
OutputJsonResolver.Targets[type] = properties;
}
}
}
return properties;
}
protected override string ResolvePropertyName(string propertyName)
{
return propertyName.ToCase(Casing.Camel);
}
#endregion
#region Assistants
private IList<JsonProperty> CreateCustomProperties(Type type, MemberSerialization memberSerialization)
{
// Hierarchy
IReadOnlyList<Type> types = this.GetTypes(type);
// Head
Type head = types.OrderByDescending(item => item.GetInterfaces().Length).FirstOrDefault();
// Sources
IList<JsonProperty> sources = base.CreateProperties(head, memberSerialization);
// Targets
IList<JsonProperty> targets = new List<JsonProperty>(sources.Count);
// Repository
IReadOnlyDistribution<Type, JsonProperty> repository = sources.ToDistribution(item => item.DeclaringType);
foreach (Type current in types.Reverse())
{
IReadOnlyPage<JsonProperty> page;
if (repository.TryGetValue(current, out page) == true)
targets.AddRange(page);
}
return targets;
}
private IReadOnlyList<Type> GetTypes(Type type)
{
List<Type> types = new List<Type>();
if (type.IsInterface == true)
types.Add(type);
types.AddRange(type.GetInterfaces());
return types;
}
#endregion
}

How can I validate different types within a collection using FluentValidation?

I have a class with a collection that needs validation. The generic on the collection takes an interface and different types can be added to the collection.
What is the cleanest path forward to creating a FluentValidation validator that supports polymorphism?
public interface IWizardStep {}
public class WizardOne : IWizardStep
{
public string Model { get; set; }
}
public class WizardTwo : IWizardStep
{
public string FirstName { get; set; }
}
public class Wizard
{
public Wizard()
{
var w1 = new WizardOne();
var w2 = new WizardTwo();
Steps = new List<IWizardStep>
{
w1,
w2
};
}
public IList<IWizardStep> Steps { get; set; }
}
public class WizardValidator : AbstractValidator<Wizard>
{
public WizardValidator()
{
RuleFor(x => x.Steps)
// Steps First where is WizardOne
// Model.NotEmpty()
// Steps First where is WizardTwo
// FirstName.NotEmpty()
}
FluentValidation doesn't support polymorphism for child collections like this out of the box, but you can add this behaviour by using a custom property validator, or by using OfType in your rule definitions.
I've written about both approaches before here:
Step 1: Create a validator for each implementor
Start by creating a validator for WizardOne and WizardTwo:
public class WizardOneValidator : AbstractValidator<WizardOne> {
public WizardOneValidator() {
RuleFor(x => x.Model).NotEmpty();
}
}
public class WizardTwoValidator : AbstractValidator<WizardTwo> {
public WizardTwoValidator() {
RuleFor(x => x.FirstName).NotEmpty();
}
}
Step 2: Create the parent validator
You have two options for defining the parent validator. The simplest approach is to use OfType, but this is less performant. The more complex option is to use a custom property validator.
Option 1: Using OfType
public WizardValidator : AbstractValidator<Wizard> {
public WizardValidator() {
RuleForEach(x => x.Steps.OfType<WizardOne>()).SetValidator(new WizardOneValidator());
RuleForEach(x => x.Steps.OfType<WizardTwo>()).SetValidator(new WizardTwoValidator());
}
}
This is the simplest approach, but calling OfType inside the call RuleFor will end up bypassing FluentValidation's expression cache, which is a potential performance hit. It also iterates the collection multiple. This may or may not be an issue for you - you'll need to decide if this has any real-world impact on your application.
Option 2: Using a custom PropertyValidator.
This uses a custom custom validator which can differentiate the underlying type at runtime:
public WizardValidator : AbstractValidator<Wizard> {
public WizardValidator() {
RuleForEach(x => x.Steps).SetValidator(new PolymorphicValidator<Wizard, IWizardStep>()
.Add<WizardOne>(new WizardOneValidator())
.Add<WizardTwo>(new WizardTwoValidator())
);
}
}
Syntactically, this isn't quite as nice, but doesn't bypass the expression cache and doesn't iterate the collection multiple times. This is the code for the PolymorphicValidator:
public class PolymorphicValidator<T, TInterface> : ChildValidatorAdaptor<T, TInterface> {
readonly Dictionary<Type, IValidator> _derivedValidators = new Dictionary<Type, IValidator>();
// Need the base constructor call, even though we're just passing null.
public PolymorphicValidator() : base((IValidator<TInterface>)null, typeof(IValidator<TInterface>)) {
}
public PolymorphicValidator<T, TInterface> Add<TDerived>(IValidator<TDerived> derivedValidator) where TDerived : TInterface {
_derivedValidators[typeof(TDerived)] = derivedValidator;
return this;
}
public override IValidator<TInterface> GetValidator(PropertyValidatorContext context) {
// bail out if the current item is null
if (context.PropertyValue == null) return null;
if (_derivedValidators.TryGetValue(context.PropertyValue.GetType(), out var derivedValidator)) {
return new ValidatorWrapper(derivedValidator);
}
return null;
}
private class ValidatorWrapper : AbstractValidator<TInterface> {
private IValidator _innerValidator;
public ValidatorWrapper(IValidator innerValidator) {
_innerValidator = innerValidator;
}
public override ValidationResult Validate(ValidationContext<TInterface> context) {
return _innerValidator.Validate(context);
}
public override Task<ValidationResult> ValidateAsync(ValidationContext<TInterface> context, CancellationToken cancellation = new CancellationToken()) {
return _innerValidator.ValidateAsync(context, cancellation);
}
public override IValidatorDescriptor CreateDescriptor() {
return _innerValidator.CreateDescriptor();
}
}
}
This will probably be implemented in the library as a first class feature at some point in the future - you can track its development here if you're interested.

Implementing a flexible searching infrastructure using nHibernate

My aim is to implement a quite generic search mechanism. Here's the general idea:
you can search based on any property of the entity you're searching for (for example- by Employee's salary, or by Department name etc.).
Each property you can search by is represented by a class, which inherits from EntityProperty:
public abstract class EntityProperty<T>
where T:Entity
{
public enum Operator
{
In,
NotIn,
}
/// <summary>
/// Name of the property
/// </summary>
public abstract string Name { get; }
//Add a search term to the given query, using the given values
public abstract IQueryable<T> AddSearchTerm(IQueryable<T> query, IEnumerable<object> values);
public abstract IQueryable<T> AddSortingTerm(IQueryable<T> query);
protected Operator _operator = Operator.In;
protected bool _sortAscending = false;
public EntityProperty(Operator op)
{
_operator = op;
}
//use this c'tor if you're using the property for sorting only
public EntityProperty(bool sortAscending)
{
_sortAscending = sortAscending;
}
}
all of the properties you're searching / sorting by are stored in a simple collection class:
public class SearchParametersCollection<T>
where T: Entity
{
public IDictionary<EntityProperty<T>,IEnumerable<object>> SearchProperties { get; private set; }
public IList<EntityProperty<T>> SortProperties { get; private set; }
public SearchParametersCollection()
{
SearchProperties = new Dictionary<EntityProperty<T>, IEnumerable<object>>();
SortProperties = new List<EntityProperty<T>>();
}
public void AddSearchProperty(EntityProperty<T> property, IEnumerable<object> values)
{
SearchProperties.Add(property, values);
}
public void AddSortProperty(EntityProperty<T> property)
{
if (SortProperties.Contains(property))
{
throw new ArgumentException(string.Format("property {0} already exists in sorting order", property.Name));
}
SortProperties.Add(property);
}
}
now, all the repository class has to do is:
protected IEnumerable<T> Search<T>(SearchParametersCollection<T> parameters)
where T : Entity
{
IQueryable<T> query = this.Session.Linq<T>();
foreach (var searchParam in parameters.SearchProperties)
{
query = searchParam.Key.AddSearchTerm(query, searchParam.Value);
}
//add order
foreach (var sortParam in parameters.SortProperties)
{
query = sortParam.AddSortingTerm(query);
}
return query.AsEnumerable();
}
for example, here's a class which implements searching a user by their full name:
public class UserFullName : EntityProperty<User>
{
public override string Name
{
get { return "Full Name"; }
}
public override IQueryable<User> AddSearchTerm(IQueryable<User> query, IEnumerable<object> values)
{
switch (_operator)
{
case Operator.In:
//btw- this doesn't work with nHibernate... :(
return query.Where(u => (values.Cast<string>().Count(v => u.FullName.Contains(v)) > 0));
case Operator.NotIn:
return query.Where(u => (values.Cast<string>().Count(v => u.FullName.Contains(v)) == 0));
default:
throw new InvalidOperationException("Unrecognized operator " + _operator.ToString());
}
}
public override IQueryable<User> AddSortingTerm(IQueryable<User> query)
{
return (_sortAscending) ? query.OrderBy(u => u.FullName) : query.OrderByDescending(u => u.FullName);
}
public UserFullName(bool sortAscending)
: base(sortAscending)
{
}
public UserFullName(Operator op)
: base(op)
{
}
}
my questions are:
1. firstly- am I even on the right track? I don't know of any well-known method for achieving what I want, but I may be wrong...
2. it seems to me that the Properties classes should be in the domain layer and not in the DAL, since I'd like the controller layers to be able to use them. However, that prevents me from using any nHibernate-specific implementation of the search (i.e any other interface but Linq). Can anybody think of a solution that would enable me to utilize the full power of nH while keeping these classes visible to upper layers? I've thought about moving them to the 'Common' project, but 'Common' has no knowledge of the Model entities, and I'd like to keep it that way.
3. as you can see by my comment for the AddSearchTerm method- I haven't really been able to implement 'in' operator using nH (I'm using nH 2.1.2 with Linq provider). any sugggestions in that respect would be appriciated. (see also my question from yesterday).
thanks!
If you need good API to query NHIbernate objects then you should use ICriteria (for NH 2.x) or QueryOver (for NH 3.x).
You over complicating DAL with these searches. Ayende has a nice post about why you should not do it
I ended up using query objects, which greatly simplified things.

How to automap a collection of components with Fluent NHibernate?

All of my entities and value objects implement marker interfaces IEntity and IValueObject. I have set them up to be treated as components like so:
public override bool IsComponent(Type type)
{
return typeof(IValueObject).IsAssignableFrom(type);
}
public override bool ShouldMap(Type type)
{
return typeof(IEntity).IsAssignableFrom(type) || typeof(IValueObject).IsAssignableFrom(type);
}
Unfortunately, this does not seem to allow entities that have collections of value objects to be automapped as component collections. For example:
public class MyEntity : IEntity
{
public IList<MyValueObject> Objects { get; set; }
}
public class MyValueObject : IValueObject
{
public string Name { get; set; }
public string Value { get; set; }
}
Is there any way to define a convention such that, any time an IEntity has an IList of a type that implements IValueObject, it gets mapped as if I had specified:
HasMany(x => x.Objects)
.Component(x => {
x.Map(m => m.Name);
x.Map(m => m.Value);
});
What I don't want to do is have to manually do these overrides for every class and write out each property for the value object again and again.
Create a new class that inherits from HasManyStep (FluentNHibernate.Automapping.Steps).
Override the ShouldMap() method with something like :
return base.ShouldMap(member) && IsCollectionOfComponents(member)
Add your logic to :
public void Map(ClassMappingBase classMap, Member member)
{ ... }
Replace the default step with your new one :
public class MyMappingConfiguration : DefaultAutomappingConfiguration
{
public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
{
var steps = base.GetMappingSteps(mapper, conventionFinder);
var finalSteps = steps.Where(c => c.GetType() != typeof(FluentNHibernate.Automapping.Steps.HasManyToManyStep)).ToList();
var idx = finalSteps.IndexOf(steps.Where(c => c.GetType() == typeof(PropertyStep)).First());
finalSteps.Insert(idx + 1, new MyCustomHasManyStep(this));
return finalSteps;
}
}
Note : You could also get the original source code of HasManyStep.cs and copy it to your project to introduce your custom logic.