Как отобразить свойство типа Dictionary <string, MyDto>, используя отображение на основе - PullRequest
0 голосов
/ 08 января 2019

У меня есть словарь, который я хочу отобразить, используя свободное отображение, и для некоторых свойств класса MyDto мне нужно добавить нормализатор.

new CreateIndexDescriptor("indexName")
.Mappings(ms => ms.Map<Entity>(e => new PutMappingDescriptor<Entity>()
 .AutoMap()
 .Properties(o => o.Object<IDictionary<string, MyDto>>(
  m => m.AutoMap().Name(f => f.SomeProperty))

определения моего класса:

class MyEntity {
...
Dictionary<string, MyDto> SomeProperty {get;set;}
...
}
class MyDto {
...
string Name {get;set;}
...
}

1 Ответ

0 голосов
/ 09 января 2019

Невозможно добавить это как явное отображение, но это происходит через динамический шаблон.

Давайте посмотрим, почему это невозможно с помощью явного отображения. Посмотрите, как Dictionary<string, MyDto> SomeProperty будет сериализован в JSON. Например

client.IndexDocument(new MyEntity 
{
    SomeProperty = new Dictionary<string, UserQuery.MyDto>
    {
        { "field_1", new MyDto { Name = "foo" } },
        { "field_2", new MyDto { Name = "bar" } }
    }
});

по умолчанию будет сериализовано как

{
  "someProperty": {
    "field_1": {
      "name": "foo"
    },
    "field_2": {
      "name": "bar"
    }
  }
}

Если бы мы хотели применить явное сопоставление к MyDto.Name, нам нужно было бы знать в точке сопоставления все ключи словаря, которые будут использоваться.

Однако вы можете настроить динамический шаблон, который будет отображать любой MyDto.Name как тип keyword, используя path_match

private static void Main()
{
    var defaultIndex = "my_index";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    var settings = new ConnectionSettings(pool)
        .DefaultIndex(defaultIndex);

    var client = new ElasticClient(settings);

    if (client.IndexExists(defaultIndex).Exists)
        client.DeleteIndex(defaultIndex);

    var createIndexResponse = client.CreateIndex(defaultIndex, c => c
        .Settings(s => s
            .NumberOfShards(1)
            .NumberOfReplicas(0)
        )
        .Mappings(m => m
            .Map<MyEntity>(mm => mm
                .AutoMap()
                .DynamicTemplates(dt => dt
                    .DynamicTemplate("MyDto", dtd => dtd
                        .PathMatch("someProperty.*.name")
                        .Mapping(dm => dm
                            .Keyword(k => k)
                        )
                    )
                )
                .Properties(p => p
                    .Object<Dictionary<string, MyDto>>(o => o
                        .Name(n => n.SomeProperty)
                    )
                )
            )
        )
    );

    var indexResponse = client.Index(new MyEntity 
    {
        SomeProperty = new Dictionary<string, UserQuery.MyDto>
        {
            { "field_1", new MyDto { Name = "foo" } },
            { "field_2", new MyDto { Name = "bar" } }
        }
    }, i => i.Refresh(Refresh.WaitFor));

    var mappingResponse = client.GetMapping<MyEntity>();
}

public class MyEntity
{
    public Dictionary<string, MyDto> SomeProperty { get; set; }
}

public class MyDto
{
    public string Name { get; set; }
}

Ответ сопоставления подтверждает, что someProperty.field_1.name и someProperty.field_2.name сопоставлены как keyword

{
  "my_index" : {
    "mappings" : {
      "myentity" : {
        "dynamic_templates" : [
          {
            "MyDto" : {
              "path_match" : "someProperty.*.name",
              "mapping" : {
                "type" : "keyword"
              }
            }
          }
        ],
        "properties" : {
          "someProperty" : {
            "properties" : {
              "field_1" : {
                "properties" : {
                  "name" : {
                    "type" : "keyword"
                  }
                }
              },
              "field_2" : {
                "properties" : {
                  "name" : {
                    "type" : "keyword"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Отступление при картировании взрыва

Возможно, вы захотите добавить в MyDto свойство для хранения ключа словаря и использовать List<MyDto> или подобную коллекцию , отображаемую как nested тип данных , а не Dictionary<string, MyDto>, если пользователи могут добавлять любые произвольные имена ключей, которые они хотят. С большим количеством словарных ключей вы рискуете взорвать карту и достичь мягкого предела максимального количества полей и большого количества разреженных полей, которые могут повлиять на производительность. С типом свойства List<MyDto> у вас не было бы этой проблемы, и вы все равно могли бы запрашивать ключевые поля за счет компромисса, что List<MyDto> может быть менее оптимальным для кода вашего приложения, чем Dictionary<string, MyDto>. Что-то, чтобы рассмотреть:)

...