Проблемы сериализации EF4 POCO WCF (без отложенной загрузки, прокси / без прокси, циклических ссылок и т. Д.)

Хорошо, я хочу убедиться, что я тщательно освещаю свою ситуацию и все, что я пробовал. Я почти уверен, что то, что мне нужно / хочу, может быть сделано, но я не нашел идеального сочетания для успеха.

Я использую Entity Framework 4 RTM и его поддержку POCO. Я хочу запросить объект (Config), который содержит отношение "многие ко многим" с другим объектом (App). Я отключаю отложенную загрузку и отключаю создание прокси для контекста и явно загружаю свойство навигации (либо с помощью .Include (), либо .LoadProperty ()). Однако, когда свойство навигации загружается (то есть приложения загружаются для данной конфигурации), загруженные объекты приложения уже содержат ссылки на конфигурации, которые были перенесены в память. Это создает круговую ссылку.

Теперь я знаю, что DataContractSerializer, который использует WCF, может обрабатывать циклические ссылки, установив для параметра preserveObjectReferences значение true. Я пробовал это с парой различных реализаций атрибутов, которые нашел в Интернете. Это необходимо для предотвращения ошибки «граф объекта содержит циклические ссылки и не может быть сериализован». Однако это не препятствует сериализации всего графа между Config и App.

Если я вызываю его через WcfTestClient.exe, я получаю исключение stackoverflow (ha!) От клиента, и меня охлаждают. Я получаю разные результаты из разных сред вызова (модульный тест C # с локальной ссылкой на веб-службу, похоже, работает нормально, хотя я все еще могу бесконечно переходить между конфигурациями и приложениями, но вызов его из среды холодного слияния возвращает только первую конфигурацию в списке и ошибки в остальных.) Моя основная цель - получить сериализованное представление графика, который я явно загружаю из EF (то есть: список конфигураций, каждый со своими приложениями, но без приложения обратно в навигацию по конфигурациям).

ПРИМЕЧАНИЕ. Я также пробовал использовать метод ProxyDataContractResolver и оставлять создание прокси-сервера включенным из моего контекста. Это взрывает жалобы на встречающиеся неизвестные типы. Я читал, что ProxyDataContractResolver не полностью работал в Beta2, но должен работать в RTM.

Для справки вот примерно то, как я запрашиваю данные в службе:

var repo = BootStrapper.AppCtx["AppMeta.ConfigRepository"] as IRepository<Config>;
repo.DisableLazyLoading();
repo.DisableProxyCreation();

//var temp2 = repo.Include(cfg => cfg.Apps).Where(cfg => cfg.Environment.Equals(environment)).ToArray();
var temp2 = repo.FindAll(cfg => cfg.Environment.Equals(environment)).ToArray();
foreach (var cfg in temp2)
{
    repo.LoadProperty(cfg, c => c.Apps);
}

return temp2;

Я думаю, что суть моей проблемы заключается в том, что при загрузке свойств навигации для объектов POCO из Entity Framework 4 он предварительно заполняет свойства навигации для объектов, уже находящихся в памяти. Это, в свою очередь, усложняет сериализацию WCF, несмотря на все усилия, приложенные для правильной обработки циклических ссылок.

Я знаю, что это много информации, но она действительно мешает мне продвигаться вперед с EF4 / POCO в нашей системе. Я нашел несколько статей и блогов, затрагивающих эти темы, но, хоть убей, я не могу решить эту проблему. Не стесняйтесь просто задавать вопросы и помогите мне провести мозговой штурм в этой ситуации.

PS: Я внедряю службы WCF с помощью сборки HEAD Spring.NET для исправления Spring.ServiceModel.Activation.ServiceHostFactory. Однако я не думаю, что это источник проблемы.

РЕДАКТИРОВАТЬ: Класс ProxyDataContractResolver работает правильно, если у меня нет циклических ссылок. (например: я делаю установщик App.Configs закрытым, что предотвращает сериализацию свойства.) Похоже, что он взрывается, когда попадает в Configs через объект App - они, похоже, не распознаются как того же типа, что и Конфиги верхнего уровня.

EDIT2: похоже, что EF или WCF не распознают, что сущности действительно равны. то есть: «Config» - это то же самое, что и конкретный «Config.Apps [x] .Configs [y]». Ключи сущностей правильно установлены в CSDL для каждой модели, и я переопределил функцию Equals () для сравнения сущностей на основе их свойства «Id». Это соответствует симптомам, поскольку ошибка циклической ссылки не возникает, но это действительно циклическая ссылка (и взрывает WcfTestClient.exe) И ProxyDataContractResolver взрывается, когда достигает уровня 'Config.Apps [x] .Configs [y]' Конфигов. (Он не знает, как сопоставить прокси-сервер Config. ProxyDataContractResolver работает иначе. Как будто он знает, как обрабатывать начальный раунд сущностей, но второй уровень он рассматривает как разные сущности.)

Вау, я могу быть многословным. Извините, ребята!


person kdawg    schedule 26.05.2010    source источник
comment
У меня сейчас точно такой же вопрос / проблема. Entity Framework 5.0. Модель сущности работает, но сериализация, похоже, не может понять, что она не должна возвращаться снова при использовании отношения многие ко многим   -  person Poul K. Sørensen    schedule 01.10.2012
comment
Была такая же проблема, решил я сам. Вот решение: stackoverflow.com/a/17063364/1386781   -  person Akash Budhia    schedule 12.06.2013
comment
WCFTestClient не может обрабатывать циклические ссылки. См. Этот [SO поток] [1] [1]: stackoverflow.com/questions/8686960/   -  person MickyD    schedule 14.06.2013


Ответы (5)


Возможно, вы захотите прочитать мою запись в блоге об этом конкретном сценарии - напишите мне, если это не помогает исправить ваше текущее затруднительное положение! Я также включил образец решения.

Пожалуйста, оставьте мне свой отзыв в любом случае, я бы очень хотел услышать от большего количества людей по этой конкретной проблеме - особенно с проблемами реализации на стороне клиента.

person RobS    schedule 13.09.2010
comment
Привет, Роб, я попробовал решение MSDN и смог вернуть Entity, но не без его объектов, в другую таблицу. Скажем, книги - ›Авторы, я получаю только книги, а авторов нет. Это потому, что они не были сериализованы? - person 123 456 789 0; 20.07.2012
comment
@LeoLuis Может быть, у вас включена ленивая загрузка? - person RobS; 29.09.2012

хммм, возможно, я не до конца понял проблему, но каждый раз, когда я сталкиваюсь с циклическими ссылками с WCF, ответ состоит в том, чтобы изменить [DataContract] в классах-нарушителях на [DataContract (IsReference = true)].

Это огромная помощь по сравнению со всей этой кучей возни с преобразователями контрактов, которая требовалась до WCF 3.5 SP1.

Надеюсь это поможет.

person tap    schedule 24.07.2010

Сегодня столкнулся с той же проблемой и использовал для ее решения Value Injecter. Это очень просто:

var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1);
var member = new Member().InjectFrom(dynamicProxyMember) as Member;

Мы не могли себе позволить отключить ProxyCreation

person Korayem    schedule 23.01.2012
comment
Вы не представляете, сколько времени вы сэкономили мне сегодня. - person Etienne Noël; 13.01.2017
comment
рад, что помог коллеге-разработчику @CoachNono - person Korayem; 22.01.2017

Попробуйте установить myContext.ContextOptions.ProxyCreationEnabled = false;

Если проблема решена (как моя), значит, вы не выполнили шаги, указанные в: http://msdn.microsoft.com/en-us/library/ee705457.aspx

Это решило проблему для меня.

person Alireza Haghshenas    schedule 27.06.2010
comment
Я сделал это обоими способами: я отключаю ленивую загрузку и отключаю создание прокси для контекста и явно загружаю свойство навигации (либо через .Include (), либо через .LoadProperty ()). Однако, когда свойство навигации загружается (то есть приложения загружаются для данной конфигурации), загруженные объекты приложения уже содержат ссылки на конфигурации, которые были перенесены в память. Это создает круговую ссылку. - person kdawg; 28.06.2010

Вы можете использовать ApplyDataContractResolverAttribute и ProxyDataContractResolver вместе с CyclicReferencesAwareAttribute. Сначала возникает ошибка, подобная этой - как будто DataContractResolver вообще не указан:

Введите 'System.Data.Entity.DynamicProxies.Whatever_E6 ...... A9' с именем контракта данных 'Whatever_E6 ...... A9: http: //schemas.datacontract.org/2004/07/System.Data .Entity.DynamicProxies 'не ожидается. Рассмотрите возможность использования DataContractResolver или добавьте любые типы, которые не известны статически, в список известных типов - например, с помощью атрибута KnownTypeAttribute или путем добавления их в список известных типов, переданный в DataContractSerializer.

Он будет работать с одним простым изменением.

В ApplyCyclicDataContractSerializerOperationBehavior конструкторы для DataContractSerializer также должны передавать DataContractResolver. Это исключено из всех версий, которые я видел в сети.

Пример:

public class ApplyCyclicDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
    private readonly Int32 _maxItemsInObjectGraph;
    private readonly bool _ignoreExtensionDataObject;

    public ApplyCyclicDataContractSerializerOperationBehavior(OperationDescription operationDescription, Int32 maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences)
        : base(operationDescription)
    {
        _maxItemsInObjectGraph = maxItemsInObjectGraph;
        _ignoreExtensionDataObject = ignoreExtensionDataObject;
    }

    public override XmlObjectSerializer CreateSerializer(Type type, String name, String ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, name, ns, knownTypes, 
            _maxItemsInObjectGraph, 
            _ignoreExtensionDataObject, 
            true, 
            null /*dataContractSurrogate*/, 
            DataContractResolver); // <-----------------------------
    }

    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, name, ns, knownTypes, 
            _maxItemsInObjectGraph, 
            _ignoreExtensionDataObject, 
            true, 
            null /*dataContractSurrogate*/, 
            DataContractResolver); // <-----------------------------
    }
}
person James    schedule 12.12.2012