My Problem
"Source" object Properties of the same class that do not exist in the View, are overwritting the same properties in the "Target" object with nulls. How do I prevent this? In affect how do I ensure only populated(not null) properties are merged into the "Target" object. I have also tried this with Automapper and failed, but I would be happy with an Automapper solution as an alternative.
I do appreciate that this "Null Mapping" question has appeared before, but I fear my situation is more involved since there are nested objects. Well I tried the suggested options and I could not get them to work. So here I am.
Huge gratitude for any help.
I appreciate this is a complex problem, and really, really appreciate any help with this, particularly if someone can produce a code sample for me. I have pulling my hair out over this for a few days :(
What I have attempted
I have 2 objects, one is the original("Target"), one("Source") is populated by a form ie a View.
The Original "Target" Object(myOrigDoc) looks like this:
The Form "Source" Object(myDoc) looks like this:
I then do the mapping:
myOrigDoc.Introduction.InjectFrom<StrNotNull>(myDoc.Introduction);
using the following injector:
public class StrNotNull: ConventionInjection
{
bool blnNotNull = false;
bool blnMatch = false;
protected override bool Match(ConventionInfo c)
{
blnNotNull = false;
blnMatch = false;
//if ((c.SourceProp.Type == typeof(string)) && (c.SourceProp.Value != null))
// blnAssignable = true;
if (c.SourceProp.Value != null)
blnNotNull = true;
if ((c.SourceProp.Name == c.TargetProp.Name) && (blnNotNull))
blnMatch = true;
return blnMatch;
}
}
and I end up with:
The Form has no "DateOfBirth" field on it, therefore I suspect Model Binding is creating a null value for the "DataOfBirth" property, on the new "MyDoc" object, when I call:
public ActionResult Index(Document myDoc)
Many thanks, Ed.
EDIT1: I believe this is a nested mapping problem due to the subclasses. Not sure how I sort this in ValueInjector.
EDIT2: Possible Automapper Solution from documentation for nested mappings, but I could not get it to work. I still get my nulls going across into the target.:
Mapper.CreateMap<XSD_Smart2.Document, XSD_Smart2.Document>
().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
Mapper.CreateMap<XSD_Smart2.DocumentIntroduction, XSD_Smart2.DocumentIntroduction>
().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
Mapper.CreateMap<XSD_Smart2.Client, XSD_Smart2.Client>().ForAllMembers(opt =>
opt.Condition(srs => !srs.IsSourceValueNull));
Update for ValueInjecter 3
public class IgnoreNulls : LoopInjection
{
protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
{
var val = sp.GetValue(source);
if (val != null)
{
tp.SetValue(target, val);
}
}
}
previous version
create a custom injection that will have this behaviour:
public class IgnoreNulls : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name
&& c.SourceProp.Value != null;
}
}
and use it:
target.InjectFrom<IgnoreNulls>(source);