【问题标题】:Using Interface Derived Classes with NEST and ElasticSearch将接口派生类与 NEST 和 ElasticSearch 一起使用
【发布时间】:2016-04-17 22:39:52
【问题描述】:

我正在尝试使用 NEST 2.X 和 Elastic Search 来持久存储用户。每个用户都包含一个角色列表,这些角色定义了他们在我们平台内的权限。

有几种不同类型的角色,每一种都派生自 IMediaDetectionRole 接口:

public class MediaDetectionUser
{
    public string Username { get; set; }
    public ICollection<IMediaDetectionRole> Roles { get; set; }

    public MediaDetectionUser()
    {
        Roles = new List<IMediaDetectionRole>();
    }
}

public interface IMediaDetectionRole
{
    string Name { get; }
    string GetDescription();
    string GetRoleType {get;}
}

[ElasticsearchType(Name="MediaDetectionAdminRole")]
public class MediaDetectionAdminRole : IMediaDetectionRole
{        
    public string Name { get { return "Admin"; } }
    public string GetDescription() { return "Admin users can create other users within the account"; }
    public string GetRoleType { get { return this.GetType().Name; } }
}

[ElasticsearchType(Name = "MediaDetectionManagerRole")]
public class MediaDetectionManagerRole : IMediaDetectionRole
{
    public string Name { get { return "Manager"; } }
    public string GetDescription() { return "Managers can modify account-level properties"; }
    public string GetRoleType { get { return this.GetType().Name; } }
}

[ElasticsearchType(Name = "MediaDetectionCreatorRole")]
public class MediaDetectionCreatorRole : IMediaDetectionRole
{
    public string Name { get { return "Creator"; } }
    public string GetDescription() { return "Creators can create new Media Detection Profiles"; }
    public string GetRoleType { get { return this.GetType().Name; } }
}

我在 ElasticSearch 中存储数据没有任何问题,但是当我去查询数据时,数据 NEST 无法确定这些角色的类型。我明白了:

Could not create an instance of type IMediaDetectionRole. 
Type is an interface or abstract class and cannot be instantiated. 
Path 'hits.hits[0]._source.roles[0].name', line 1, position 343.

将嵌套对象数据映射回正确的类类型的正确方法是什么?

非常感谢!

-Z

【问题讨论】:

  • 文档elastic.co/guide/en/elasticsearch/client/net-api/current/… 中解释了这个确切的用例:)
  • 感谢 Martijn,我知道这对于顶级对象是如何工作的。但这些实例是 MediaDetectionUser 对象中列表的一部分。我不清楚如何使用 .Types() 或 ConcreteTypeSelector 来解析嵌套对象的类型。
  • 对于 DTO 中的集合,您可以使用 [JsonPropery(ItemTypeHandling = TypeHandling.Objects],这会将 $type 添加到序列化结果中,并且 json.net 将能够将其反序列化回正确的类。
  • 啊哈!就这样搞定了!我将记录我的修复并在此处发布答案。我不明白这个问题更多的是在 JsonSerialization 方面,而不是在 NEST/ES 方面。一如既往,非常感谢@MartijnLaarman!

标签: c# .net elasticsearch interface nest


【解决方案1】:

好吧,我想这不是 NEST/ES 问题,而是 JSON.NET 问题。显然,这个问题的解决方案包括告诉 JSON.NET 为列表的每个成员提供类型提示。

根据@MartijnLaarman 的建议,我在 Roles 属性中添加了一个 [JsonProperty] 属性。见下文:

public class MediaDetectionUser
{
    public string Username { get; set; }

    //This JsonProperty helps reference the types during deserialization
    [JsonProperty("Roles", ItemTypeNameHandling = TypeNameHandling.All)]
    public ICollection<IMediaDetectionRole> Roles { get; set; }

    public MediaDetectionUser()
    {
        Roles = new List<IMediaDetectionRole>();
    }
}

这是一个 JSON 示例,它出现在 ElasticSearch 的 _source 中:

Roles: [
  {
    $type: "MediaDetectionFrontend.ServiceModel.Types.MediaDetectionAdminRole, MediaDetectionFrontend.ServiceModel",
    name: "Admin",
    getRoleType: "MediaDetectionAdminRole"
  },
  {
    $type: "MediaDetectionFrontend.ServiceModel.Types.MediaDetectionCreatorRole, MediaDetectionFrontend.ServiceModel",
    name: "Creator",
    getRoleType: "MediaDetectionCreatorRole"
  },
  {
    $type: "MediaDetectionFrontend.ServiceModel.Types.MediaDetectionEditorRole, MediaDetectionFrontend.ServiceModel",
    name: "Editor",
    getRoleType: "MediaDetectionEditorRole"
  }
]

您可以看到 $type 属性现在提供了 List 中每个元素的完整类型描述符。

非常感谢 @MartijnLaarman 帮助我解决了这个问题,尽管它与 ElasticSearch 和 NEST 无关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多