C# neo4jclient异构数据返回

C# neo4jclient异构数据返回,c#,neo4jclient,C#,Neo4jclient,假设我有以下内容(简化): 公共类项目 { 公共字符串名称{get;set;} 公共字符串类型{get;set;} } 公共级护甲:道具 { 公共int AC{get;set;} 公共装甲(){Type=“Armor”;} } 公共级武器:道具 { 公共整数损坏{get;set;} 公共装甲(){Type=“武器”;} } 公共级演员 { ... } 公共类HasItem:RelationshipRelationshipAllowingSourceNode、IRelationshipAllowi

假设我有以下内容(简化):

公共类项目
{
公共字符串名称{get;set;}
公共字符串类型{get;set;}
}
公共级护甲:道具
{
公共int AC{get;set;}
公共装甲(){Type=“Armor”;}
}
公共级武器:道具
{
公共整数损坏{get;set;}
公共装甲(){Type=“武器”;}
}
公共级演员
{
...
}
公共类HasItem:RelationshipRelationshipAllowingSourceNode、IRelationshipAllowingTargetNode
{
公共只读字符串TypeKey=“HasItem”;
public HasItem(节点引用目标项,整数计数=1)
:base(targetItem,new ItemProps{Count=Count})
{
}
公共重写字符串RelationshipTypeKey
{
获取{return TypeKey;}
}
}
有了这个设置,我可以轻松地创建一个与演员相关的武器、盔甲等的异构列表。但我似乎不知道怎么把他们弄出来。我使用这个方法(再次简化)来获得所有相关项的列表,但它将它们作为项全部输出。我想不出怎样才能把它们做成真正的类型。我可以使用类型字段来确定类型,但似乎没有任何动态构建返回的方法:

public IEnumerable<Item> Items
    {
        get
        {
            return
            GameNode
                .GraphClient
                .Cypher
                .Start(new { a = Node.ByIndexLookup("node_auto_index", "Name", Name) })
                .Match("(a)-[r:HasItem]-(i)")
                .Return<Item>("i") // Need something here to return Armor, Weapon, etc as needed based on the Type property
                .Results;
        }
    }
公共IEnumerable项
{
得到
{
返回
游戏节点
.GraphClient
塞弗先生
.Start(新的{a=Node.ByIndexLookup(“Node\u auto\u index”,“Name”,Name)})
.Match(“(a)-[r:HasItem]-(i)”)
.Return(“i”)//这里需要一些东西根据类型属性返回装甲、武器等
.结果;
}
}
我发现了一个糟糕的解决方法,返回类型和NodeID,并通过switch语句运行列表,该语句对NodeID执行.Get并将其强制转换为正确的类型。但这是不灵活和低效的。我可以为每个派生类运行一个查询,并将它们连接在一起,但想到这一点,我的皮肤就会蠕动


这似乎是一个常见的问题,但我在网上找不到任何东西。有什么想法吗?

问题在于如何将数据存储在Neo4J中,并通过Json.net序列化回来

假设我有一把剑:

var sword = new Weapon{
    Name = "Sword 12.32.rc1",
    Type = "Sword"
    Damage = 12
};
如果我将其序列化为neo4j:
graphClient.Create(剑)一切正常,在内部我们现在有一个Json表示,它看起来像这样:

{ "Name" : "Sword 12.32.rc1", "Type": "Sword", "Damage": "12"}
这里没有计算机可以用来推断这实际上是“剑”类型的信息,因此如果您带回类型
的集合,它只能带回两个属性
Name
type

因此,我可以想到两种解决方案,其中任何一种都不是很好,但它们都可以为您提供一个查询解决方案。第一个(最糟糕的)是创建一个“SuperItem”,它将派生类的所有属性放在一起,因此:

public class SuperItem { Name, Type, Damage, AC } //ETC
但这太可怕了,而且有点让等级制度变得毫无意义。第二个选择,虽然不是很好,但更好——是使用
词典
获取数据:

var query = GraphClient
    .Cypher
    .Start(new {n = actorRef})
    .Match("n-[:HasItem]->item")
    .Return(
    item => new
    {
        Item = item.CollectAs<Dictionary<string,string>>()
    });

var results = query.Results.ToList();
将打印:

Key: Type, Value: Sword
Key: Damage, Value: 12
Key: Name, Value: 12.32.rc1
现在我们有了一个属性字典,我们可以创建一个扩展类来解析它:

public static class DictionaryExtensions
{
    public static Item GetItem(this Dictionary<string, string> dictionary)
    {
        var type = dictionary.GetTypeOfItem().ToLowerInvariant();
        var json = dictionary.ToJson();
        switch (type)
        {
            case "sword":
                return GetItem<Weapon>(json);

            case "armor":
                return GetItem<Armor>(json);

            default:
                throw new ArgumentOutOfRangeException("dictionary", type, string.Format("Unknown type: {0}", type));
        }
    }

    private static string GetTypeOfItem(this Dictionary<string, string> dictionary)
    {
        if(!dictionary.ContainsKey("Type"))
            throw new ArgumentException("Not valid type!");

        return dictionary["Type"];
    }

    private static string ToJson(this Dictionary<string, string> dictionary)
    {
        var output = new StringBuilder("{");

        foreach (var property in dictionary.OrderBy(k => k.Key))
            output.AppendFormat("\"{0}\":\"{1}\",", property.Key, property.Value);

        output.Append("}");
        return output.ToString();
    }

    private static Item GetItem<TItem>(string json) where TItem: Item
    {
        return JsonConvert.DeserializeObject<TItem>(json);
    }
}
公共静态类字典扩展
{
公共静态项GetItem(此字典)
{
var type=dictionary.GetTypeOfItem().ToLowerInvariant();
var json=dictionary.ToJson();
开关(类型)
{
案例“剑”:
返回GetItem(json);
案例“盔甲”:
返回GetItem(json);
违约:
抛出新ArgumentOutOfRangeException(“dictionary”,type,string.Format(“未知类型:{0}”,type));
}
}
私有静态字符串GetTypeOfItem(此字典)
{
if(!dictionary.ContainsKey(“Type”))
抛出新ArgumentException(“无效类型!”);
返回字典[“类型”];
}
私有静态字符串ToJson(此字典)
{
var输出=新的StringBuilder(“{”);
foreach(dictionary.OrderBy中的var属性(k=>k.Key))
AppendFormat(“\“{0}\”:\“{1}\”,”,property.Key,property.Value);
output.Append(“}”);
返回output.ToString();
}
私有静态项GetItem(字符串json),其中TItem:Item
{
返回JsonConvert.DeserializeObject(json);
}
}
并使用类似于:

var items = new List<Item>();
foreach (var data in results)
    foreach (Node<Dictionary<string, string>> item in data.Item)
         items.Add(item.Data.GetItem());
var items=newlist();
foreach(结果中的var数据)
foreach(data.item中的节点项)
items.Add(item.Data.GetItem());
其中,
将是您所追求的类型


我知道这不太好,但它确实可以让您进行一次查询。

问题在于数据如何存储在Neo4J中,并通过Json.net序列化回来

假设我有一把剑:

var sword = new Weapon{
    Name = "Sword 12.32.rc1",
    Type = "Sword"
    Damage = 12
};
如果我将其序列化为neo4j:
graphClient.Create(剑)一切正常,在内部我们现在有一个Json表示,它看起来像这样:

{ "Name" : "Sword 12.32.rc1", "Type": "Sword", "Damage": "12"}
这里没有计算机可以用来推断这实际上是“剑”类型的信息,因此如果您带回类型
的集合,它只能带回两个属性
Name
type

因此,我可以想到两种解决方案,其中任何一种都不是很好,但它们都可以为您提供一个查询解决方案。第一个(最糟糕的)是创建一个“SuperItem”,它将派生类的所有属性放在一起,因此:

public class SuperItem { Name, Type, Damage, AC } //ETC
但这太可怕了,而且有点让等级制度变得毫无意义。第二个选择,虽然不是很好,但更好——是使用
词典
获取数据:

var query = GraphClient
    .Cypher
    .Start(new {n = actorRef})
    .Match("n-[:HasItem]->item")
    .Return(
    item => new
    {
        Item = item.CollectAs<Dictionary<string,string>>()
    });

var results = query.Results.ToList();
将打印:

Key: Type, Value: Sword
Key: Damage, Value: 12
Key: Name, Value: 12.32.rc1
现在我们有了一个属性字典,我们可以创建一个扩展类来解析它:

public static class DictionaryExtensions
{
    public static Item GetItem(this Dictionary<string, string> dictionary)
    {
        var type = dictionary.GetTypeOfItem().ToLowerInvariant();
        var json = dictionary.ToJson();
        switch (type)
        {
            case "sword":
                return GetItem<Weapon>(json);

            case "armor":
                return GetItem<Armor>(json);

            default:
                throw new ArgumentOutOfRangeException("dictionary", type, string.Format("Unknown type: {0}", type));
        }
    }

    private static string GetTypeOfItem(this Dictionary<string, string> dictionary)
    {
        if(!dictionary.ContainsKey("Type"))
            throw new ArgumentException("Not valid type!");

        return dictionary["Type"];
    }

    private static string ToJson(this Dictionary<string, string> dictionary)
    {
        var output = new StringBuilder("{");

        foreach (var property in dictionary.OrderBy(k => k.Key))
            output.AppendFormat("\"{0}\":\"{1}\",", property.Key, property.Value);

        output.Append("}");
        return output.ToString();
    }

    private static Item GetItem<TItem>(string json) where TItem: Item
    {
        return JsonConvert.DeserializeObject<TItem>(json);
    }
}
公共静态类字典扩展
{
公共静态项GetItem(此字典字典)