we are currently wrestling with the following problem in our C# code with NEST.
Say we have a parent object with that contains a property that refers to an abstract class:
(simplified example)
class ParentObject { public AbstractSource Src { get; set; } }
abstract class AbstractSource { public string SrcField {get; set; }}
class Source1 : AbstractSource { public string Source1Field {get; set; }}
class Source2 : AbstractSource { public string Source2Field {get; set; }}
We are creating our index using Nest with a mapping using AutoMap.
...Map(m => m.AutoMap())
However, Automap only creates a mapping for the fields on AbstractSource and not on it's children (Source1 and Source2). Is there a way to solve this?
We tried adding extra mappings by:
.AutoMap()
.Properties(p =>
p.Object(o => o.Name("src").AutoMap())
p.Object(o => o.Name("src").AutoMap())
but this does not work (only the mapping of 1 of the 2 sources appears).
Of course our problem can be partly solved by
declaring every property that is on a child manually using .Properties()
using DynamicMappings, and predefining mappings for field types
However, we would prefer not to do this as it is very verbose and not very practical on a large project (a lot of inside knowledge about mappings and the nest syntax is required) and it is a lot cleaner and easier to have AutoMap look at the mapping attributes on our poco's.
This is a C# language constraint; since the Src property is of type AbstractSource, automapping will only ever pick up properties declared on that type.
You could use the PropertyWalker that walks C# type properties to map these in an implementation. Something like
public class Promise<TValue> : IPromise<TValue> where TValue : class
{
public Promise(TValue value)
{
Value = value;
}
public TValue Value { get; }
}
public class MultiPropertyWalker
{
Type[] _types;
public MultiPropertyWalker(params Type[] types)
{
_types = types;
}
public IProperties GetProperties()
{
var allProperties = new Properties();
foreach (var type in _types)
{
var walker = new PropertyWalker(type, null);
var properties = walker.GetProperties();
foreach (var property in properties)
allProperties[property.Key] = property.Value;
}
return allProperties;
}
}
then use it with
client.CreateIndex("index", c=> c
.Mappings(m => m
.Map<ParentObject>(mm => mm
.AutoMap()
.Properties(p => p
.Object<AbstractSource>(o => o
.Name(n => n.Src)
.AutoMap()
.Properties(op => new Promise<IProperties>(
new MultiPropertyWalker(typeof(AbstractSource), typeof(Source1), typeof(Source2)).GetProperties())
)
)
)
)
)
);
Bear in mind that for any derived types that implement a property with the same name but different type, the last one mapped will supercede any previously mapped properties.
Apache, Apache Lucene, Apache Hadoop, Hadoop, HDFS and the yellow elephant
logo are trademarks of the
Apache Software Foundation
in the United States and/or other countries.