none
wcf data services (odata) обновление связанных обьектов RRS feed

  • Вопрос

  •  

    как то можно заставить wcf ds на клиенте обновлять связи автоматически после загрузки данных?

    вот например есть у меня такая модель в ef 4.1 code first

     

    class User
    
    {
    
    	public Guid ID { get; set; }
    
    	public Profile Profile { get; set; }
    
    	public Guid? ProfileID { get; set; }
    
    }
    
    class Profile
    
    {
    
    	public Guid ID { get; set; }
    
    	public string Description { get; set; }
    
    }
    

     

    теперь если загрузить сначала User а потом связанный Profile то у User свойство Profile будет все так же null

     

    var dataContext = new DataContext();
    
    dataContext.MergeOption = MergeOption.OverwriteChanges; 
    
    var user = dataContext.Users.Where(u=>u.Name == "Test").Single();
    
    var profile = dataContext.Profiles.Where(p.ID == user.ProfileID).Single();
    
    // and in this moment user.Profile is null
    
    Trace.WriteLine( user.Profile == null ); // true
    

     

    что то можно сделать что бы DataServiceContext привязал user.Profile к только что загруженному обьекту по ключам используя схему которую DataServiceContext  хранит в файле service.edmx

    только не говорите про expand, я знаю что это, вся проблема в том что у меня есть несколько обьектов many to many, и если пользоваться только expand приходится загружать много данных в том числе повторно одно и тоже.







    • Изменено sky_cp 1 февраля 2012 г. 5:46
    1 февраля 2012 г. 0:17

Ответы

  • > сделать на сервере Include или на клиенте Expand я могу, но тогда в некоторых случаях мне придется делать несколько Include т.е. несколько свойств + их внутренних свойств например User.Group.AllowerOperation из за чего придется загружать много данных самих по себе и вдобавок много лишних данны

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

    2. При запросе данных можно передавать экспрешн на инклуды и селекты

    Отпишите как решите свою проблему, пожалуйста. С WCF работал (Silverlight to db), проблема кажется слегка странной

    промежуточная модель это что именно? если репозиторий, то да можно я об этом думал, но есть одна проблема, например если у меня уже полностью загружены все категории и связанные продукты, затем пользователь из другого приложения изменяет продукт, добавляет к нему категорию, на сервере срабатывает обработчик изменения продуктов, я посылаю на другой клиент сообщение что продукт такой то изменился, клиент загружает этот продукт даже с expand categories и тут такая проблема, это изменение видно только если смотреть данные через products , а если через categories.products то там все по старому т.е. никаких изменений, и получается чтобы иметь последнюю версию связи между продуктами и категориями надо вручную обновить navigation property на другом конце так сказать.. 

     

                var cachedDataRepository = GetCachedDataRepository(); // наш локальный кэш
                Product loadedProduct; // только что загруженный продукт с expand("Categories"), точно известно что это актуальная версия
    
                // берем из нашего репозитория все уже загруженные категории связаные с этим продуктом
                var linkedCategories =
                    cachedDataRepository.Categories.Where(c => c.Products.Any(p => p == loadedProduct));
    
                //идем по всем категориям не и удаляем или добавляем всязь
                foreach (var category in linkedCategories)
                {
                    //если в категории уже есть этот продукт а в продукте нету категории очевидно что пользователь произвел удаление
                    //проверку делаем исходя из данных loadedProduct так как они только что загружены и актуальны
                    bool isDeleteLinkAction =  loadedProduct.Categories.Contains(category) == false;
                    if(isDeleteLinkAction)
                    {
                        category.Products.Remove(loadedProduct);
                    }
                }
    

    примерно вот так.. 


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

    я никак не могу понять почему команда разрабатывающая клиентскую часть data services не использовала трекер entity framework, могли бы вынести оттуда базовый класс и наследовать его как в ef так и в wcf ds, и получить эту функциональность без существенных затрат, или могли бы и сами реализовать, csdl файл есть а там и вся информация про связи, можно были и атрибуты внедрить при генерации клиентских классов описывающие что к чему привязано.

    насчет второго пункта, не совсем понимаю что это меняет и как относится к проблеме?

     

    я думаю решить эту проблему ручками так сказать примерно как выше написал т.е восстановить связи вручную, еще думаю попробовать на клиенте создать entity framework context и наполнять уже его новыми данными, но он будет без базы дынных, просто в памяти, главное что бы быстро работало та и вообще что бы работало..

    есть идеи как бы это все реализовать без ручной работы а то сущностей много и связей тоже..








    • Помечено в качестве ответа sky_cp 2 февраля 2012 г. 13:28
    • Снята пометка об ответе sky_cp 2 февраля 2012 г. 13:28
    • Изменено sky_cp 2 февраля 2012 г. 13:44
    • Помечено в качестве ответа Abolmasov DmitryModerator 5 февраля 2012 г. 14:58
    2 февраля 2012 г. 13:13

Все ответы

  • Include пробовали?

    Примерно так: 

    var user = dataContext.Users.Include("Profile").Single(u=>u.Name == "Test");
    
    // and in this moment user.Profile is not null
    
    Trace.WriteLine( user.Profile == null ); // false
    

    • Предложено в качестве ответа iSanSYS 1 февраля 2012 г. 20:04
    • Отменено предложение в качестве ответа sky_cp 2 февраля 2012 г. 0:51
    1 февраля 2012 г. 20:03
  • И да - проверьте, может у пользователя действительно профиль пуст ;)
    1 февраля 2012 г. 20:04
  • > если загрузить сначала User а потом связанный Profile то у User свойство Profile будет все так же null


    если я правильно понял, то см. Using DbContext in EF 4.1 Part 6: Loading Related Entities;
    а для DataContext см. DataLoadOptions.LoadWith Method
      
     

    1 февраля 2012 г. 20:08
  • спасибо за помощь , но это все из другой оперы..

    Include используется в EF, DataLoadOptions в linq2sql, а мне нужно решение для wcf data services на клиентской стороне,

    DataServiceContext Class 

    и да User.Profile не пустой

     

     

    Trace.WriteLine(dataContext.Users.Expand("Profile").Where(u=>u.Name == "Test").Single().Profile != null) // true
    

     

    я вас возможно не много сбил с толку упоминанием entity framework, он используется только на сервере для доступа к БД и доступен для клиента только через OData (Wcf Data Service),  на клиенте используется автоматически созданные классы и классы из библиотеки System.Data.Services.Client.dll

    сделать на сервере Include или на клиенте Expand я могу, но тогда в некоторых случаях мне придется делать несколько Include т.е. несколько свойств + их внутренних свойств например User.Group.AllowerOperation из за чего придется загружать много данных самих по себе и вдобавок много лишних данных

    мне нужно лишь восстановить связи между уже загруженными обьектами т.е. вот есть User с уже загруженным User.Group и после этого отдельно загружается AllowedOperations, и получается такая ситуация, у меня в DataServiceContext.Entities есть и User с его User.Group и AllowedOperations, вот только User.Group.AllowdOperations у всех обьектов пустая коллекция.

    я как бы могу получить интересующие меня значения из  DataServiceContext.Entities фильтруя по ключам но во первых это не удобно, получается некое sql программирование на C#, правда с linq это не сложно и я бы остановился на этом решении но есть вторая проблема, производительность, в Entities лежат все загруженные обьекты, и получается надо по всем пробежаться что бы найти несколько нужных обьектов, и последняя проблема Entities не реализует INotifyCollectionChanged, а у меня клиент на wpf и мне это нужно для биндингов.

    я пока писал текст пришел к мысли, если реализовать задуманное средствами wcf data services не получится, то можно на клиенте создать ef 4.1 DbContext и все загруженные данные кидать туда что бы он позаботился о востановлении связей, если конечно от такое умеет делать на клиентской стороне.. что скажите, получится средствами Data Services реализовать задуманное или придется еще и entity framework использовать?

    2 февраля 2012 г. 0:18
  • > сделать на сервере Include или на клиенте Expand я могу, но тогда в некоторых случаях мне придется делать несколько Include т.е. несколько свойств + их внутренних свойств например User.Group.AllowerOperation из за чего придется загружать много данных самих по себе и вдобавок много лишних данны

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

    2. При запросе данных можно передавать экспрешн на инклуды и селекты

    Отпишите как решите свою проблему, пожалуйста. С WCF работал (Silverlight to db), проблема кажется слегка странной

    2 февраля 2012 г. 8:46
  • > сделать на сервере Include или на клиенте Expand я могу, но тогда в некоторых случаях мне придется делать несколько Include т.е. несколько свойств + их внутренних свойств например User.Group.AllowerOperation из за чего придется загружать много данных самих по себе и вдобавок много лишних данны

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

    2. При запросе данных можно передавать экспрешн на инклуды и селекты

    Отпишите как решите свою проблему, пожалуйста. С WCF работал (Silverlight to db), проблема кажется слегка странной

    промежуточная модель это что именно? если репозиторий, то да можно я об этом думал, но есть одна проблема, например если у меня уже полностью загружены все категории и связанные продукты, затем пользователь из другого приложения изменяет продукт, добавляет к нему категорию, на сервере срабатывает обработчик изменения продуктов, я посылаю на другой клиент сообщение что продукт такой то изменился, клиент загружает этот продукт даже с expand categories и тут такая проблема, это изменение видно только если смотреть данные через products , а если через categories.products то там все по старому т.е. никаких изменений, и получается чтобы иметь последнюю версию связи между продуктами и категориями надо вручную обновить navigation property на другом конце так сказать.. 

     

                var cachedDataRepository = GetCachedDataRepository(); // наш локальный кэш
                Product loadedProduct; // только что загруженный продукт с expand("Categories"), точно известно что это актуальная версия
    
                // берем из нашего репозитория все уже загруженные категории связаные с этим продуктом
                var linkedCategories =
                    cachedDataRepository.Categories.Where(c => c.Products.Any(p => p == loadedProduct));
    
                //идем по всем категориям не и удаляем или добавляем всязь
                foreach (var category in linkedCategories)
                {
                    //если в категории уже есть этот продукт а в продукте нету категории очевидно что пользователь произвел удаление
                    //проверку делаем исходя из данных loadedProduct так как они только что загружены и актуальны
                    bool isDeleteLinkAction =  loadedProduct.Categories.Contains(category) == false;
                    if(isDeleteLinkAction)
                    {
                        category.Products.Remove(loadedProduct);
                    }
                }
    

    примерно вот так.. 


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

    я никак не могу понять почему команда разрабатывающая клиентскую часть data services не использовала трекер entity framework, могли бы вынести оттуда базовый класс и наследовать его как в ef так и в wcf ds, и получить эту функциональность без существенных затрат, или могли бы и сами реализовать, csdl файл есть а там и вся информация про связи, можно были и атрибуты внедрить при генерации клиентских классов описывающие что к чему привязано.

    насчет второго пункта, не совсем понимаю что это меняет и как относится к проблеме?

     

    я думаю решить эту проблему ручками так сказать примерно как выше написал т.е восстановить связи вручную, еще думаю попробовать на клиенте создать entity framework context и наполнять уже его новыми данными, но он будет без базы дынных, просто в памяти, главное что бы быстро работало та и вообще что бы работало..

    есть идеи как бы это все реализовать без ручной работы а то сущностей много и связей тоже..








    • Помечено в качестве ответа sky_cp 2 февраля 2012 г. 13:28
    • Снята пометка об ответе sky_cp 2 февраля 2012 г. 13:28
    • Изменено sky_cp 2 февраля 2012 г. 13:44
    • Помечено в качестве ответа Abolmasov DmitryModerator 5 февраля 2012 г. 14:58
    2 февраля 2012 г. 13:13
  • про второй пункт забей

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

    2 февраля 2012 г. 15:07
  • думал об этом, возможно так и поступлю.. на счет велосипедов, гуглил но так и не нашел удобного решения, все что удалось найти модифицированный шаблон T4, который использует entity framework 4.0 для трекинга, но запустить не удалось, он для старой версии wcf ds, потом исправлю и посмотрю как оно работает на деле..

    2 февраля 2012 г. 19:36
  • на сколько я помню, при помощи T4 можно удобно сгенерить код (т.е. ручками пишешь логику генерации), а потом в приложении можно его юзать, но могу врать.
    3 февраля 2012 г. 8:28
  • я создал новую похожую тему в другом разделе, возможно более подходящем..
    4 февраля 2012 г. 3:36