# Custom mapping .NET field names

**URL:** <https://discuss.elastic.co/t/custom-mapping-net-field-names/78557>\
**Category:** Elasticsearch\
**Created:** [March 14, 2017, 4:06pm UTC](https://discuss.elastic.co/t/custom-mapping-net-field-names/78557 "2017-03-14T16:06:39Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![muhandis](https://avatars.discourse-cdn.com/v4/letter/m/71c47a/32.png) [@muhandis](https://discuss.elastic.co/u/muhandis)\
**Post date:** [March 14, 2017, 4:06pm UTC](https://discuss.elastic.co/t/custom-mapping-net-field-names/78557/1 "2017-03-14T16:06:39Z")

</div>

I have an existing ES index, and I need to "dynamically" specify how my .NET field names are mapped should be mapped to the ES/JSON field names.

It seems that I can't easily do this because everything is stuck behind the fluent methods. Even if I were to create my own IClrTypeMapping, every field is stuck behind an Expression:

> <https://github.com/elastic/elasticsearch-net/blob/master/src/Nest/CommonAbstractions/ConnectionSettings/ClrTypeMapping.cs#L25>

> <https://github.com/elastic/elasticsearch-net/blob/master/src/Nest/CommonAbstractions/ConnectionSettings/ClrTypeMapping.cs#L95>

Is there really no way around this? It seems like I have to either

1. Ditch NEST altogether
2. Modify NEST to not require Expressions everywhere.
3. Dynamically create expressions

All of which I'd really rather not do.

Fluent is nice but there's always the alternative for situations where it isn't suitable. Yet all I can find is being forced to use the fluent methods everywhere.

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [March 16, 2017, 1:41am UTC](https://discuss.elastic.co/t/custom-mapping-net-field-names/78557/2 "2017-03-16T01:41:58Z")

</div>

[Take a look at the documentation on Field inference](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/field-inference.html); there are numerous ways available in NEST to achieve this:

If you need to change only a few field names then you can use:

1. `Rename()` on `ConnectionSettings`

2. `Name` property on the relevant attribute value

3. If using the default serializer ([JSON.Net](http://JSON.Net)), then using the `JsonProperty` attribute

If you need to **change all field names** according to some convention, then this can be done with `.DefaultFieldNameInferrer()` on `ConnectionSettings`

```
var settings = new ConnectionSettings()
    // upper case all property names. argument is the property name inferred from the POCO
    .DefaultFieldNameInferrer(p => p.ToUpperInvariant();

var client = new ElasticClient(settings);
```

---

<div class="post-metadata">

**Author:** ![muhandis](https://avatars.discourse-cdn.com/v4/letter/m/71c47a/32.png) [@muhandis](https://discuss.elastic.co/u/muhandis)\
**Post date:** [March 16, 2017, 2:12am UTC](https://discuss.elastic.co/t/custom-mapping-net-field-names/78557/3 "2017-03-16T02:12:33Z")

</div>

Thank you for taking the time to answer, but I think you misunderstood my question. I was probably unclear.

I'm aware of all three ways. None work for what I need - I can only determine the "new" name by knowing the `MemberInfo` of the .NET type to be mapped. The mapping is completely dynamic. i.e. I have a dynamically created map of `MemberInfo => string (jsonElementName)`

1. `Rename()` on `ConnectionSettings` does not work because it's completely restricted to an Expression. As you said, it's only suitable for a few fields.

2. Since mappings are dynamic, Attributes do not work either. However, I hadn't realized that the serializer is [Json.NET](http://Json.NET). I'll look into changing the mappings there, thank you.

3. `DefaultFieldNameInferrer` only provides the original name. The `DeclaringType` and `Type` information of the field is completely lost. I need both to infer the name.

For now, I've solved the problem by creating a new `ClrTypeMapping` with dynamically created Expressions. IMO the use of `Expression` for the `Properties` is too restrictive and gives rise to problems like the one I've encountered:

```
    config.InferMappingFor<MyMappedType>(f => GetMappingFromBson<MyMappedType>("myIndexName", "myESMappingName"));

    private static ClrTypeMapping<T> GetMappingFromBson<T>(string indexName, string mappingName = null) where T: class
    {

        var mapping = new ClrTypeMapping<T> { IndexName = indexName, TypeName = mappingName ?? (typeof(T)).Name};
        var bsonMap = BsonClassMap.LookupClassMap(typeof(T));

        mapping.Properties = new List<IClrTypePropertyMapping<T>>();
        foreach (var m in bsonMap.AllMemberMaps)
        {
            var expr = CreatePropertyExpression<T>(m.MemberInfo);
            var p = new RenamePropertyMapping<T>(expr, m.ElementName);
            mapping.Properties.Add(p);
        }

        return mapping;

    }

    private static Expression<Func<T, object>> CreatePropertyExpression<T>(MemberInfo memberInfo)
    {
        var parameter = Expression.Parameter(typeof(T), "p");
        var member = Expression.MakeMemberAccess(parameter, memberInfo);
        var asObject = Expression.Convert(member, typeof(object));
        return Expression.Lambda<Func<T, object>>(asObject, parameter);
    }
```

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [March 16, 2017, 3:03am UTC](https://discuss.elastic.co/t/custom-mapping-net-field-names/78557/4 "2017-03-16T03:03:24Z")

</div>

I did misunderstand your question 😄

The client works on the premise that you have POCOs to represent the documents you have in Elasticsearch.

The advantage of using member access expressions to determine field names from POCO property types is that it provides compile time safety and easy refactorability.

If you don't have POCOs to represent documents and instead need to build a mapping by reflecting over the properties of a type at runtime, you'll need to do more work as you've done or alternatively, you can cast `ConnectionSettings` to `IConnectionSettingsValues` in order to access the explicitly implemented `PropertyMappings` property and add the mappings this way

```
void Main()
{
	var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
	var defaultIndex = "default-index";
	var connectionSettings = new ConnectionSettings(pool, new InMemoryConnection())
			.DefaultIndex(defaultIndex);
                
    var connectionSettingsValues = (IConnectionSettingsValues)connectionSettings;

    foreach (var memberInfo in typeof(Document).GetMembers())
    {
        connectionSettingsValues.PropertyMappings.Add(memberInfo, new PropertyMapping { Name = $"foo{memberInfo.Name}" });
    }
                
	var client = new ElasticClient(connectionSettings);

    client.Index(new Document
    {
        Name = "org name",
        Value = 1
    });
}

public class Document
{
    public string Name { get; set; }
    
    public int Value { get; set; }
}

```

will serialize to

```
POST http://localhost:9200/default-index/document?pretty=true 
{
  "fooName": "org name",
  "fooValue": 1
}
```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [April 13, 2017, 3:03am UTC](https://discuss.elastic.co/t/custom-mapping-net-field-names/78557/5 "2017-04-13T03:03:24Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
