Целостность корневой сериализации Protobuf-net

У меня есть два объекта, которые ссылаются друг на друга.

    [JsonObject(IsReference = true)]
    [DataContract(IsReference = true, Namespace = "http://schemas.datacontract.org/2004/07/TrackableEntities.Models")]
    [ProtoContract]
    public class ProtoBufObject : ITrackable
    {
        [DataMember(Order = 3)]
        public Guid Oid { get; set; }
        [DataMember(Order = 4)]
        [ProtoMember(4, AsReference = true)]
        public ChildProtoBufObject child { get; set; }
        [DataMember(Order = 1)]
        public TrackingState TrackingState { get; set; }
        [DataMember(Order = 2)]
        public ICollection<string> ModifiedProperties { get; set; }
    }

    [JsonObject(IsReference = true)]
    [DataContract(IsReference = true, Namespace = "http://schemas.datacontract.org/2004/07/TrackableEntities.Models")]
    [ProtoContract]
    public class ChildProtoBufObject : ITrackable
    {

        [DataMember(Order = 3)]
        public Guid Oid { get; set; }

        [DataMember(Order = 4)]
        [ProtoMember(4, AsReference = true)]
        public ProtoBufObject parent { get; set; }

        [DataMember(Order = 1)]
        public TrackingState TrackingState { get; set; }
        [DataMember(Order = 2)]
        public ICollection<string> ModifiedProperties { get; set; }
    }

На клиенте я создаю экземпляры этих объектов и создаю «ассоциации».

 ProtoBufObject parent = new ProtoBufObject()
         {
             Oid = Guid.NewGuid()
         };
         ChildProtoBufObject child = new ChildProtoBufObject()
         {
             Oid = Guid.NewGuid()
         };
         parent.child = child;
         child.parent = parent;

Объекты будут сериализованы следующим образом:

    ProtoBufFormatter formatter = new ProtoBufFormatter();
    HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
    requestMessage.Content = new ObjectContent<SearchParameters>(searchParameters, formatter);

А затем они будут отправлены по http на вебапи, где будут десериализованы с помощью WebApiContrib.Formatting.ProtoBuf.

В контроллере Webapi я получаю объекты с правильными отношениями, НО целостность отношений пошла не так. Я выгружаю объекты с Json в файл с этим фрагментом кода:

 string json = JsonConvert.SerializeObject(samples);
            //write string to file
            string oid = samples.First().Oid.ToString();
            System.IO.File.WriteAllText(@"D:\JsonTest\dummypath" + oid + ".txt", json);

А вот как выглядит этот текстовый файл

[{
    "$id": "1",
    "TrackingState": 0,
    "ModifiedProperties": null,
    "Oid": "8c00ea73-ac84-4130-b1a8-61e1df89f9bf",
    "child": {
        "$id": "2",
        "TrackingState": 0,
        "ModifiedProperties": null,
        "Oid": "81026a01-7de2-4045-ac0a-314b3fd7360c",
        "parent": {
            "$id": "3",
            "TrackingState": 0,
            "ModifiedProperties": null,
            "Oid": "8c00ea73-ac84-4130-b1a8-61e1df89f9bf",
            "child": {
                "$ref": "2"
            }
        }
    }
}]

у ребенка есть "новый" родитель с id=3 вместо ref=1. Родительский элемент с идентификатором 3 имеет правильную ссылку на дочерний элемент.

Таким образом, кажется, что объект верхнего уровня не будет настроен правильно. Это огромная проблема с Entity Framework (вот почему я придумал эту проблему), потому что она использует ссылку на тип, а не только на свойства (что правильно).

Я также пробовал это с ProtoContract(DefaultRefencetype=true), но это сделало его еще хуже. Затем я получил от родителя с id=3 новый дочерний элемент с id=4.

Мой вопрос: как я могу заставить целостность объектов работать?

Я хочу:

[{
    "$id": "1",
    "TrackingState": 0,
    "ModifiedProperties": null,
    "Oid": "8c00ea73-ac84-4130-b1a8-61e1df89f9bf",
    "child": {
        "$id": "2",
        "TrackingState": 0,
        "ModifiedProperties": null,
        "Oid": "81026a01-7de2-4045-ac0a-314b3fd7360c",
        "parent": {
            "$ref": "1"
            }
        }
    }
}]

Изменить: строка Entity Framework

dbContext.Set<ProtoBufObject>.AddRange(myObjects);

выдает InvalidOperationException, потому что целостность моделей (родительская, дочерняя.родительская) различается.

Additional information: Conflicting changes to the role 'foo_bar_Target' of the relationship 'Entities.Context.foo_bar' have been detected.

Если я использую сериализатор Newtonsoft.Json на стороне клиента и отправляю его через WebApi (я использую те же объекты с теми же отношениями, что и в моем тесте Protobuf), Entity Framework может обрабатывать объекты. Поэтому должны быть какие-то различия между десериализованными объектами из Json и Protobuf. Вот почему я снова сериализовал объекты, чтобы увидеть различия.

Я также добавил в свой метод Put проверку ссылок:

if (protoBufObject != protoBufObject.child.parent)
{
    throw new Exception("Instance integrity differs!");
}

как и ожидалось от файла json, это исключение выдается, поэтому ссылки действительно повреждены.

При запуске WebApi я использую следующий код:

        config.Formatters.Add(new ProtoBufFormatter());

Там проблема? Нужно ли мне добавить дополнительную информацию в форматтеры?


person Oliver Müller    schedule 11.06.2014    source источник
comment
Что, кроме JSON, заставляет вас думать, что отношения разорваны? Например, это прекрасно работает: pastie.org/9280110 — можете ли вы показать что-то, демонстрирующее, что код ведет себя не так, как ожидал?   -  person Marc Gravell    schedule 11.06.2014
comment
Я отредактировал свой пост со строкой Entity Framework, которая заставляет меня думать, что отношения разорваны.   -  person Oliver Müller    schedule 12.06.2014
comment
На корневой объект ссылается дочерний объект, и по какой-то причине protobuf-net создает копию при сериализации вместо правильной ссылки. Обходным путем было бы поместить все в другой корневой объект.   -  person Sjoerd222888    schedule 22.06.2014
comment
Есть ли у вас какое-либо решение или это оставшаяся проблема?   -  person Oliver Müller    schedule 16.10.2014