У меня есть приложение 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 я генерирую ключ и проверяю, существует ли он в базе данных.Если это так, и объект, с которым я работаю, отсоединен, я применяю эти значения;в противном случае, я принудительно отключаю и применяю значения, которые работают вокруг добавленного состояния из любых предыдущих вызовов вставки.
Есть ли лучший способ сделать это? Я чувствую, что делаюслишком много работы здесь.