neo4jclient heterogenous data return
本文关键字:return data heterogenous neo4jclient | 更新日期: 2023-09-27 18:30:40
假设我有以下内容(简化):
public class Item
{
public String Name { get; set; }
public String Type { get; set; }
}
public class Armor : Item
{
public int AC { get; set; }
public Armor () { Type = "Armor"; }
}
public class Weapon : Item
{
public int Damage { get; set; }
public Armor () { Type = "Weapon"; }
}
public class Actor
{
...
}
public class HasItem : Relationship<ItemProps>, IRelationshipAllowingSourceNode<Actor>, IRelationshipAllowingTargetNode<Item>
{
public readonly string TypeKey = "HasItem";
public HasItem ( NodeReference targetItem, int count = 1 )
: base(targetItem, new ItemProps { Count = count })
{
}
public override string RelationshipTypeKey
{
get { return TypeKey; }
}
}
通过这种设置,我可以轻松创建与Actor相关的武器,盔甲等的异构列表。但我似乎不知道如何把它们弄出来。我有这种方法(再次简化)来获取所有相关项目的列表,但它将它们全部作为项目输出。我不知道如何让它们成为它们的实际类型。我可以使用 Type 字段来确定类型,但似乎没有任何动态构建返回的方法:
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;
}
}
我发现了一个糟糕的解决方法,我返回类型和 NodeID 并通过执行 .获取 NodeID 并将其转换为正确的类型。但这是不灵活和低效的。我可以为每个派生类运行一个查询并将它们连接在一起,但一想到这一点,我的皮肤就会爬行。
这似乎是一个常见问题,但我在网上找不到任何东西。有什么想法吗?
问题是数据如何存储在 Neo4J 中,并通过 Json.net 序列化回来。
假设我有一把剑:
var sword = new Weapon{
Name = "Sword 12.32.rc1",
Type = "Sword"
Damage = 12
};
如果我将其序列化为 neo4j:graphClient.Create(sword);
一切都很好,在内部我们现在有一个 Json 表示,它看起来像这样:
{ "Name" : "Sword 12.32.rc1", "Type": "Sword", "Damage": "12"}
这里没有计算机可以用来推断这实际上是"剑"类型的信息,因此如果您带回类型Item
的集合,它只能带回两个属性Name
和Type
。
因此,我能想到两种解决方案,其中一种都不是很好,但两者都可以通过一个查询解决方案为您提供帮助。第一个(最糟糕的)是创建一个"SuperItem",它将派生类中的所有属性放在一起,因此:
public class SuperItem { Name, Type, Damage, AC } //ETC
但这太可怕了,而且有点使等级制度毫无意义。第二个选项,虽然不是很好,但更好 - 是使用Dictionary
来获取数据:
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();
如果您运行:
foreach (var data in results2.SelectMany(item => item.Item, (item, node) => new {item, node}).SelectMany(@t => @t.node.Data))
Console.WriteLine("Key: {0}, Value: {1}", data.Key, data.Value);
会打印出来:
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);
}
}
并使用类似以下内容:
var items = new List<Item>();
foreach (var data in results)
foreach (Node<Dictionary<string, string>> item in data.Item)
items.Add(item.Data.GetItem());
items
将是你所追求的类型。
我知道这不是很好,但它确实可以让您进行一个查询。