Приложение SL RIA - Вставка и обновление с использованием стандартного сгенерированного кода не работает - есть ли лучший способ? - PullRequest
1 голос
/ 14 декабря 2011

У меня есть приложение Silverlight RIA, в котором я делюсь моделями и доступом к данным между веб-приложением MVC и приложением Silverlight, используя директивы компилятора, и для сервера, чтобы посмотреть, в каком контексте я работаю, я бы проверил, чтобы увидеть,Объект ChangeSet был не нулевым (то есть я работал под RIA, а не с MvC).Все работает хорошо, но у меня были проблемы с кодом по умолчанию, сгенерированным методами доменной службы.

Допустим, у меня была сущность Person, которая принадлежала определенным группам (сущность Group).Объект Person имеет коллекцию групп, которые я добавляю или удаляю.После внесения изменений приложение SL вызывает сервер для сохранения изменений.Я заметил, что записи групповых сущностей будут вставлены первыми.Это нормально, так как я изменяю существующего человека.Однако, поскольку каждая сущность группы также имеет ссылку на существующего человека, вызов AddObject пометит весь график - включая человека, которого я пытаюсь изменить, - как добавленный.Затем, когда вызывается оператор Update, сгенерированный по умолчанию код будет пытаться присоединить человека, который теперь находится в состоянии добавленного, к контексту с не слишком веселыми результатами.

Когда я делаюПри первоначальном вызове объекта или набора объектов в запросе все EntityKeys для объектов заполняются. Один раз на клиенте, затем EntityKey заполняется для каждого объекта.Когда объект возвращается от клиента для обновления на сервере, EntityKey имеет значение null.Я создал новый проект RIA Services и убедился, что это так.Я использую RIA Services SP1 и не использую композицию.Я вроде понимаю проблему EntityKey - отслеживание изменений выполняется в двух разных контекстах.EF не знает о отслеживании изменений, выполненных на стороне SL.Тем не менее, он передает обратно граф объектов, включая связанные сущности, поэтому использование AddObject является проблемой, если я сначала не проверю базу данных на наличие объекта с тем же ключом.

У меня есть код, который работает.Я не знаю, как ХОРОШО это работает, но сегодня я провожу дополнительное тестирование, чтобы увидеть, что происходит.Вот оно:

    /// <summary>
    /// Updates an existing object.
    /// </summary>
    /// <typeparam name="TBusinessObject"></typeparam>
    /// <param name="obj"></param>
    protected void Update<TBusinessObject>(TBusinessObject obj) where TBusinessObject : EntityObject
    {
        if (this.ChangeSet != null)
        {

            ObjectStateManager objectStateManager = ObjectContext.ObjectStateManager;
            ObjectSet<TBusinessObject> entitySet = GetEntitySet<TBusinessObject>();
            string setName = entitySet.EntitySet.Name;
            EntityKey key = ObjectContext.CreateEntityKey(setName, obj);
            object dbEntity;

 if (ObjectContext.TryGetObjectByKey(key, out dbEntity) && obj.EntityState == System.Data.EntityState.Detached)
            {
                // An object with the same key exists in the DB, and the entity passed 
                // is marked as detached.
                // Solution: Mark the object as modified, and any child objects need to 
                // be marked as Unchanged as long as there is no Domainoperation.
                ObjectContext.ApplyCurrentValues(setName, obj);
            }

            else if (dbEntity != null)
            {
                // In this case, tryGetObjectByKey said it failed, but the resulting object is
                // filled in, leading me to believe that it did in fact work.
                entitySet.Detach(obj); // Detach the entity
                try
                {
                    ObjectContext.ApplyCurrentValues(setName, obj); // Apply the changes to the entity in DB
                }
                catch (Exception)
                {
                    entitySet.Attach(obj); // Re-attach the entity
                    ObjectContext.ApplyCurrentValues(setName, obj); // Apply the changes to the entity in DB'
                }

            }
            else
            {
                // Add it..? Update must have been called mistakenly.
                entitySet.AddObject(obj);
            }
        }
        else
            DirectInsertUpdate<TBusinessObject>(obj);
    }

Краткое руководство: Если ChangeSet имеет значение null, я не в контексте RIA и, следовательно, могу вызвать другой метод для обработки вставки / обновления и немедленного сохранения.Это прекрасно работает, насколько я могу судить.Для RIA я генерирую ключ и проверяю, существует ли он в базе данных.Если это так, и объект, с которым я работаю, отсоединен, я применяю эти значения;в противном случае, я принудительно отключаю и применяю значения, которые работают вокруг добавленного состояния из любых предыдущих вызовов вставки.

Есть ли лучший способ сделать это? Я чувствую, что делаюслишком много работы здесь.

Ответы [ 2 ]

0 голосов
/ 25 мая 2012

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

После работы со службами RIA в течение полутора лет я нахожусь в лагере, который считает, что службы RIA хороши для работы с небольшими и менее сложными приложениями. Если вы можете использовать [Composite] для своих сущностей, чего я не мог для многих моих сущностей, то у вас все в порядке.

Службы RIA могут очень быстро объединить небольшие приложения, в которых вы хотите использовать сущность из EF, но если вы хотите использовать POCO или вы предвидите, что ваше приложение станет сложным в будущем, я бы остановился на создании POCO на службе заканчивайте и пропускайте их через обычный WCF и используйте общие поведения, делая ваши POCO частичными классами и передавая код поведения клиенту. Когда вы пытаетесь создать модели, которые работают одинаково на клиенте и сервере, мне пришлось написать нелепое количество кода, чтобы он работал.

Это определенно возможно сделать, я сделал это; но есть много обручей, через которые вы должны перепрыгнуть, чтобы все работало хорошо, и я никогда полностью не принимал во внимание такие вещи, как списки предварительной загрузки вашей общей модели для использования на клиенте, в то время как сервер не нуждался в них каждый раз и фактически замедлил загрузку веб-страницы без необходимости и противостоял, написав хакерские вызовы методов, которые мне пришлось принять на клиенте. (Извините за разбег.) Техника, которую я выбрал, определенно имела свои проблемы.

0 голосов
/ 02 февраля 2012

В этом случае, когда вы добавляете объекты группы в Person.Groups, я бы подумал о том, чтобы просто сохранить Person и ожидать, что RIA будет обрабатывать группы для меня.шаг назад, как вы пытаетесь сохранить ваши изменения?Вы не должны сохранять / обновлять объекты по одному.Все, что вам нужно сделать, это вызвать DomainContext.SubmitChanges, и все ваши изменения должны быть сохранены.

Я работаю с довольно сложными проектами, и мне редко приходится касаться добавления / обновления кода.

...