Запрос Cypher возвращает исключение Create Bug Exception

Я получаю следующую ошибку, когда пытаюсь получить результаты cyper-запроса в Neo4JClient.

Ошибка:

Neo4jClient encountered an exception while deserializing the response from the server. This is likely a bug in Neo4jClient.    
Please open an issue at https://bitbucket.org/Readify/neo4jclient/issues/new    
To get a reply, and track your issue, ensure you are logged in on BitBucket before submitting.    
Include the full text of this exception, including this message, the stack trace, and all of the inner exception details.    

Include the full type definition of <>f__AnonymousType3`2[[Neo4jClient.Node`1[[IQS_ACL.Nodes.User, IQS ACL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Neo4jClient, Version=1.0.0.594, Culture=neutral, PublicKeyToken=null],[Neo4jClient.Node`1[[IQS_ACL.Nodes.SecurityRelationshipObject, IQS ACL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Neo4jClient, Version=1.0.0.594, Culture=neutral, PublicKeyToken=null]].

Include this raw JSON, with any sensitive values replaced with non-sensitive equivalents:    

{    
  "columns" : [ "Node", "Rels" ],    
  "data" : [ [ {    
    "paged_traverse" : "http://localhost:7474/db/data/node/7690/paged/traverse/{returnType}{?pageSize,leaseTime}",    
    "outgoing_relationships" : "http://localhost:7474/db/data/node/7690/relationships/out",    
    "data" : {    
      "Name" : "root"    
    },    
    "traverse" : "http://localhost:7474/db/data/node/7690/traverse/{returnType}",    
    "all_typed_relationships" : "http://localhost:7474/db/data/node/7690/relationships/all/{-list|&|types}",    
    "all_relationships" : "http://localhost:7474/db/data/node/7690/relationships/all",    
    "property" : "http://localhost:7474/db/data/node/7690/properties/{key}",    
    "self" : "http://localhost:7474/db/data/node/7690",    
    "properties" : "http://localhost:7474/db/data/node/7690/properties",    
    "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/7690/relationships/out/{-list|&|types}",    
    "incoming_relationships" : "http://localhost:7474/db/data/node/7690/relationships/in",    
    "incoming_typed_relationships" : "http://localhost:7474/db/data/node/7690/relationships/in/{-list|&|types}",    
    "extensions" : {    
    },    
    "create_relationship" : "http://localhost:7474/db/data/node/7690/relationships"    
  }, {    
    "start" : "http://localhost:7474/db/data/node/7690",    
    "data" : {    
      "W" : 3,    
      "R" : 3,    
      "ReadablePermissions" : "+R+W",    
      "X" : 1    
    },    
    "property" : "http://localhost:7474/db/data/relationship/9351/properties/{key}",    
    "self" : "http://localhost:7474/db/data/relationship/9351",    
    "properties" : "http://localhost:7474/db/data/relationship/9351/properties",    
    "type" : "SECURITY",    
    "extensions" : {    
    },    
    "end" : "http://localhost:7474/db/data/node/7696"    
  } ], [ {    
    "paged_traverse" : "http://localhost:7474/db/data/node/7690/paged/traverse/{returnType}{?pageSize,leaseTime}",    
    "outgoing_relationships" : "http://localhost:7474/db/data/node/7690/relationships/out",    
    "data" : {    
      "Name" : "root"    
    },    
    "traverse" : "http://localhost:7474/db/data/node/7690/traverse/{returnType}",    
    "all_typed_relationships" : "http://localhost:7474/db/data/node/7690/relationships/all/{-list|&|types}",    
    "all_relationships" : "http://localhost:7474/db/data/node/7690/relationships/all",    
    "property" : "http://localhost:7474/db/data/node/7690/properties/{key}",    
    "self" : "http://localhost:7474/db/data/node/7690",    
    "properties" : "http://localhost:7474/db/data/node/7690/properties",    
    "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/7690/relationships/out/{-list|&|types}",    
    "incoming_relationships" : "http://localhost:7474/db/data/node/7690/relationships/in",    
    "incoming_typed_relationships" : "http://localhost:7474/db/data/node/7690/relationships/in/{-list|&|types}",    
    "extensions" : {    
    },    
    "create_relationship" : "http://localhost:7474/db/data/node/7690/relationships"    
  }, {    
    "start" : "http://localhost:7474/db/data/node/7690",
    "data" : {
      "W" : 3,
      "R" : 3,
      "ReadablePermissions" : "+R+W",
      "X" : 1
    },
    "property" : "http://localhost:7474/db/data/relationship/9351/properties/{key}",
    "self" : "http://localhost:7474/db/data/relationship/9351",
    "properties" : "http://localhost:7474/db/data/relationship/9351/properties",
    "type" : "SECURITY",
    "extensions" : {
    },
    "end" : "http://localhost:7474/db/data/node/7696"
  } ] ]}

Код:

var groups = clientConnection.Cypher
                .Start(new { n = "node(" + folderID + ")" })
                .Match("n<-[r:SECURITY]-x, x<-[v:IS_MEMBER_OF_GROUP*]-b where b.Name = '"+userName+"'")
                .ReturnDistinct((x, r) => new
                {
                    Node = x.As<Node<User>>(),
                    Rels = r.As<Node<SecurityRelationshipObject>>()
                });

var results = groups.Results;
It throws on the .Results();

Если я запускаю запрос:

START n=node(7706) MATCH n<-[r:SECURITY]-x, x<-[v:IS_MEMBER_OF_GROUP*]-b where b.Name = 'user1' RETURN distinct x AS Node, r AS Rels;

в консоли возвращает:

Node[7700]{Name:"root"} | :SECURITY[9369] {ReadablePermissions:"+R+W",R:3,W:3,X:1} |

Билет Bitbucket: https://bitbucket.org/Readify/neo4jclient/issue/153/cypher-query-returns-create-bug-exception

Определения классов:

public class User
{
    //CMIS Object Properties
    public string ObjectId { get; set; }
    public string BaseTypeId { get; set; }
    public string ObjectTypeId { get; set; }
    public IList<string> SecondaryObjectTypeIds { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CreatedBy { get; set; }
    public string CreationDate { get; set; }
    public string LastModifiedBy { get; set; }
    public string LastModificationDate { get; set; }
    public string ChangeToken { get; set; }
}

public class UserGroup
{
    //CMIS Object Properties
    public string ObjectId { get; set; }
    public string BaseTypeId { get; set; }
    public string ObjectTypeId { get; set; }
    public IList<string> SecondaryObjectTypeIds { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CreatedBy { get; set; }
    public string CreationDate { get; set; }
    public string LastModifiedBy { get; set; }
    public string LastModificationDate { get; set; }
    public string ChangeToken { get; set; }
}

public class RelationshipObject
{
    //CMIS Object Properties
    public string ObjectId { get; set; }
    public string BaseTypeId { get; set; }
    public string ObjectTypeId { get; set; }
    public Array SecondaryObjectTypeIds { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CreatedBy { get; set; }
    public string CreationDate { get; set; }
    public string LastModifiedBy { get; set; }
    public string LastModificationDate { get; set; }
    public string ChangeToken { get; set; }

    //RelationshipObject Properties
    public string sourceId { get; set; }
    public string targetId { get; set; }
}

public class SecurityRelationshipObject : RelationshipObject
{
    //CMIS Object Properties
    public IList<string> SecondaryObjectTypeIds { get; set; }
    public string ReadablePermissions { get; set; }
    public int R { get; set; }
    public int W { get; set; }
    public int X { get; set; }
}

Определения отношений:

public class RelationshipUserGroupToFolder: Relationship<SecurityRelationshipObject>, IRelationshipAllowingSourceNode<UserGroup>, IRelationshipAllowingTargetNode<FolderObject>
{
    string RelationshipName;

    public RelationshipUserGroupToFolder(string RelationshipName, NodeReference targetNode, SecurityRelationshipObject relationshipTypeObject)
        : base(targetNode, relationshipTypeObject)
    {
        this.RelationshipName = RelationshipName;
    }

    public override string RelationshipTypeKey
    {
        get { return RelationshipName; }
    }
}

public class RelationshipUserGroupToUserGroup : Relationship<RelationshipObject>, IRelationshipAllowingSourceNode<UserGroup>, IRelationshipAllowingTargetNode<UserGroup>
{
    string RelationshipName;

    public RelationshipUserGroupToUserGroup(string RelationshipName, NodeReference targetNode, RelationshipObject relationshipTypeObject)
        : base(targetNode, relationshipTypeObject)
    {
        this.RelationshipName = RelationshipName;
    }

    public override string RelationshipTypeKey
    {
        get { return RelationshipName; }
    }
}

Существует несколько разных типов, таких как RelationshipUserToFolder (безопасность) или RelationshipUserToUseGroup (IS_MEMBER_OF_GROUP).


person Shaun Groenewald    schedule 08.10.2013    source источник
comment
Можете ли вы предоставить определения классов User и SecurityRelationshipObject, спасибо!   -  person Charlotte Skardon    schedule 08.10.2013
comment
Привет, я добавил это к вопросу. Спасибо.   -  person Shaun Groenewald    schedule 08.10.2013
comment
Отлично, и является ли RelationshipObject (базовый класс для SecurityRelationshipObject) отношением?   -  person Charlotte Skardon    schedule 08.10.2013
comment
Да, на самом деле он выглядит почти так же, как SecurityRelationshipObject (по крайней мере, закомментированные части - это то, что в нем). Я быстро отредактирую.   -  person Shaun Groenewald    schedule 08.10.2013
comment
ОК, вероятно, потребуется дополнительная информация: 1. Как определяется связь Security, 2. Как определяется связь IsMemberOfGroup... Однако в качестве примечания: вы пытались изменить Rels = r.As<Node<SecurityRelationshipObject>>() на Rels = r.As<RelationshipInstance<Security<SecurityRelationshipObject>>>()   -  person Charlotte Skardon    schedule 08.10.2013
comment
Попробовал быстро, все равно не работает. var kUser = ... .Results выглядит точно так же, как и группы, и это почему-то работает. Разница между ними в том, что это группы clientConnection.CreateRelationship(root, new RelationshipUserGroupToFolder("SECURITY", rootFolder, new SecurityRelationshipObject { ReadablePermissions = "+W", R = 1, W = 3, X = 1 })); и clientConnection.CreateRelationship(user1, new RelationshipUserToFolder("SECURITY", user1Home, new SecurityRelationshipObject { ReadablePermissions = "+R+W+X", R = 3, W = 3, X = 3 }));.   -  person Shaun Groenewald    schedule 08.10.2013


Ответы (1)


Я почти уверен, что проблема связана с битом кода Rels = ..., так как я почти уверен, что вы пытаетесь преобразовать Relationship в Node, а Neo4j не знает, как это сделать. Кроме того, JSON.NET (и, по ассоциации, neo4jclient) не знает, как десериализовать SecurityRelationshipObject, поскольку он (и его базовый класс) имеет свойство, определенное для типов Array и IList, только коллекции IEnumerable<> могут быть десериализованы.

Для этого .ReturnDistinct должен выглядеть так:

/* Rest of query here */
.ReturnDistinct((x, r) => new
{
    Node = x.As<Node<User>>(),
    Rels = r.As<RelationshipInstance<SecurityRelationshipObject>>()
});

и объекты данных должны выглядеть так:

public class RelationshipObject {
    /* Other Properties */
    public IEnumerable<string> SecondaryObjectTypeIds { get; set }
}

public class SecurityRelationshipObject : RelationshipObject {
    /* Other Properties */
    public new IEnumerable<string> SecondaryObjectTypeIds { get;set; }
}

Хотя очевидно, что вам не нужно это свойство в версии "Безопасность", так как оно уже есть в базовом классе, но если оно у вас есть, вы должны использовать ключевое слово new, чтобы указать, что оно заменяет версия базового класса.

Если у вас ничего нет в этих свойствах, он будет нормально десериализоваться, что может объяснить, почему Node = x.As<Node<User>>() работает нормально, даже если у вас там также есть IList<>.

Ниже приведена небольшая программа, которая при запуске (Tester.Run()) должна выводить (Chris has known jeff since yesterday) — можете ли вы попробовать это в консольном приложении и посмотреть, работает ли это для вас? Вы должны иметь возможность копировать / вставлять его целиком.


using System;
using Neo4jClient;

public static class Tester
{
    public static void Run()
    {
        var client = new GraphClient(new Uri("http://localhost.:7474/db/data"));
        client.Connect();
        NodeReference<User> rootRef = AddData(client);

        var query = client.Cypher.Start(new {n = rootRef})
            .Match("n-[r:KNOWS]->other")
            .Return((other, r) => new
            {
                Other = other.As<Node<User>>(),
                Knows = r.As<RelationshipInstance<KnowsData>>()
            });

        var results = query.Results;

        foreach (var result in results)
            Console.WriteLine("Chris has known {0} since {1}", result.Other.Data.Name, result.Knows.Data.Since);
    }

    private static NodeReference<User> AddData(IGraphClient client)
    {
        var chris = new User {Name = "Chris"};
        var jeff = new User {Name = "Jeff"};

        NodeReference<User> chrisRef = client.Create(chris);
        NodeReference<User> jeffRef = client.Create(jeff);

        client.CreateRelationship(chrisRef, new Knows(jeffRef, new KnowsData {Since = "Yesterday"}));
        return chrisRef;
    }
}

public class User { public string Name { get; set; } }
public class KnowsData { public string Since { get; set; } }

public class Knows : Relationship<KnowsData>, IRelationshipAllowingSourceNode<User>, IRelationshipAllowingTargetNode<User>
{
    public Knows(NodeReference targetNode, KnowsData data) : base(targetNode, data) {}
    public override string RelationshipTypeKey { get { return "KNOWS"; } }
}
person Charlotte Skardon    schedule 08.10.2013
comment
Итак, если я удалю часть rels, это сработает. Я просто не уверен, как это изменить сейчас. Я попробовал несколько вещей: Rels = r.As<RelationshipInstance<SecurityRelationshipObject>>() и ваш r.As<RelationshipInstance<RelationshipUserGroupToFolder>>(), который выдает Error 17 'IQS_ACL.Relationships.RelationshipUserGroupToFolder' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TData' in the generic type or method 'Neo4jClient.RelationshipInstance<TData>' C:\Users\Shaun\Documents\Visual Studio 2012\Projects\IQS ACL\IQS ACL` - person Shaun Groenewald; 08.10.2013
comment
Ах! Полностью забыл о конструкторе по умолчанию, посмотрите правку в моем ответе - извините! - person Charlotte Skardon; 08.10.2013
comment
Удивительно, так что это позволяет использовать его в шифрованном запросе, но, похоже, у него нет свойств, когда я foreach над ним (R, W, X и т. д.) - person Shaun Groenewald; 08.10.2013
comment
Измените RelationshipUserGroupToFolder на SecurityRelationshipObject (я отредактирую ответ) - person Charlotte Skardon; 08.10.2013
comment
Это решает проблему со свойствами (как в коде находит ее), но теперь снова ломается с тем же исключением, когда я заменяю его на SecurityRelationshipObject - person Shaun Groenewald; 08.10.2013
comment
Вы возвращаетесь: r.As<RelationshipInstance<SecurityRelationshipObject>>() верно? - person Charlotte Skardon; 08.10.2013
comment
Да я: var groups = clientConnection.Cypher .Start(new { folder = "node(" + folderID + ")" }) .Match("folder<-[r:SECURITY]-userGroup, userGroup<-[:IS_MEMBER_OF_GROUP*]-user where user.Name = '" + userName + "'") .ReturnDistinct((userGroup, r) => new { Node = userGroup.As<Node<User>>(), Rels = r.As<RelationshipInstance<SecurityRelationshipObject>>() }); - person Shaun Groenewald; 08.10.2013
comment
Я добавил «тестовую» программу, чтобы вы могли проверить, работает ли она. Насколько я могу судить, это близкая аналогия вашей ситуации, поэтому мне любопытно, работает ли она для вас. - person Charlotte Skardon; 08.10.2013
comment
Тестовая программа работает на моей стороне (просто добавил ее в свою dll и запустил в консольном приложении) - person Shaun Groenewald; 09.10.2013
comment
Я немного растерялся без кода, на который можно посмотреть. Боюсь, насколько я вижу, он должен работать. В общем, можете ли вы посмотреть на SecurityRelationshipObject и RelationshipObject, в частности на свойство SecondaryObjectTypeIds, изменить его на: public IEnumerable<string> SecondaryObjectTypeIds { get; set; } в базовом классе и удалить его из класса SecurityRelationshipObject (если можете) - person Charlotte Skardon; 09.10.2013
comment
Получил его репликацию в моем коде, это это определения Array и IList, вам нужно преобразовать все экземпляры IList и Array в IEnumerable<> (и это должна быть общая версия). - person Charlotte Skardon; 09.10.2013
comment
Привет, да, это был массив. Он находится в dll другого сотрудника, и я его вообще не заметил. Большое спасибо за помощь, хотя это просто оказалось небрежным кодированием с нашей стороны. Я также изменил его на IList, который, кажется, работает (очевидно, он наследуется от IEnumerable). - person Shaun Groenewald; 09.10.2013
comment
Если ты когда-нибудь будешь в Кейптауне, я должен тебе пиво. - person Shaun Groenewald; 09.10.2013
comment
Рад, что в конце концов мы добрались до этого - я использую ICollection везде и потратил довольно много времени, пытаясь понять, почему он не будет десериализоваться :) - person Charlotte Skardon; 09.10.2013