Обновление Entity Framework со связанной сущностью - PullRequest
3 голосов
/ 23 октября 2009

Я использую EF, чтобы попытаться обновить сущность с помощью ASP.NET. Я создаю сущность, устанавливаю ее свойства, затем передаю ее обратно в EF на отдельном слое с идентификатором, чтобы можно было применить изменение. Я делаю это потому, что храню идентификатор объекта, только когда он привязан к элементам управления пользовательского интерфейса.

Все работает для стандартных свойств, но я не могу обновить Category.ID продукта (связанной сущности). Я пробовал EntityKey, EntityReference и некоторые другие, но идентификатор категории не сохраняется. Вот что у меня есть:

Product product = new Product();
product.CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", categoryId);
product.Name = txtName.Text.Trim();
... other properties
StockControlDAL.EditProduct(productId, product);

public static void EditProduct(int productId, Product product) {
 using(var context = new ShopEntities()) {
     var key = new EntityKey("ShopEntities.Products", "ProductID", productId);
     context.Attach(new Product() { ProductID = productId, EntityKey = key });
     context.AcceptAllChanges();
     product.EntityKey = key;
     product.ProductID = productId;
     context.ApplyPropertyChanges("ShopEntities.Products", product);
     context.SaveChanges();
 }
}

Я действительно хочу использовать EF, но у меня, похоже, возникли некоторые проблемы с его использованием в ASP.NET.

Ответы [ 2 ]

6 голосов
/ 23 октября 2009

Причина, по которой это не получается, в два раза.

  1. Чтобы обновить ссылку (т.е. Product.Category), вы также должны иметь исходное значение ссылки в контексте.
  2. ApplyPropertyChanges (...) применяется только к обычным / скалярным свойствам сущности, ссылка остается без изменений

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

Product product = new Product();
// Use a stub because it is much easier.
product.Category = new Category {CategoryID = selectedCategoryID};
product.Name = txtName.Text.Trim();
... other properties

StockControlDAL.EditProduct(productId, originalCategoryID);


public static void EditProduct(Product product, int originalCategoryID ) {
 using(var context = new ShopEntities()) 
 {
     // Attach a stub entity (and stub related entity)
     var databaseProduct = new Product { 
             ProductID = product.ProductID, 
             Category = new Category {CategoryID = originalCategoryID}
         };
     context.AttachTo("Products", databaseProduct);

     // Okay everything is now in the original state
     // NOTE: No need to call AcceptAllChanges() etc, because 
     // Attach puts things into ObjectContext in the unchanged state

     // Copy the scalar properties across from updated product 
     // into databaseProduct in the ObjectContext
     context.ApplyPropertyChanges("ShopEntities.Products", product);

     // Need to attach the updated Category and modify the 
     // databaseProduct.Category but only if the Category has changed. 
     // Again using a stub.
     if (databaseProduct.Category.CategoryID != product.Category.CategoryID)
     {
         var newlySelectedCategory = 
                 new Category {
                     CategoryID = product.Category.CategoryID
                 };

         context.AttachTo("Categories", newlySelectedCategory)

         databaseProduct.Category = newlySelectedCategory;

     }

     context.SaveChanges();
 }
}

Это сделает работу, если не будет опечаток и т. Д.

0 голосов
/ 23 октября 2009

Это принятый ответ на этот вопрос Сильно типизированный ASP.NET MVC с Entity Framework

context.AttachTo(product.GetType().Name, product);
ObjectStateManager stateMgr = context.ObjectStateManager;
ObjectStateEntry stateEntry = stateMgr.GetObjectStateEntry(model);
stateEntry.SetModified();
context.SaveChanges();

Вы пробовали это?

[Обновлено, код сверху не работает]

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

public partial class Product
{
    public int? CategoryID
    {
        set
        {  
           CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", value);
        }
        get
        {
            if (CategoryReference.EntityKey == null)
                return null;

            if (CategoryReference.EntityKey.EntityKeyValues.Count() > 0)
                return (int)CategoryReference.EntityKey.EntityKeyValues[0].Value;
            else
                return null;
        }
    }
}

и это сработало для меня (на этот раз точно):

System.Data.EntityKey key = new System.Data.EntityKey("ShopEntities.Products", "ProductID", productId);
        object originalItem;   

        product.EntityKey = key;
        if (context.TryGetObjectByKey(key, out originalItem))
        {
            if (originalItem is EntityObject &&
                ((EntityObject)originalItem).EntityState != System.Data.EntityState.Added)
            {
                Product origProduct = originalItem as Product;   
                origProduct.CategoryID == product.CategoryID;//set foreign key again to change the relationship status           
                context.ApplyPropertyChanges(
                    key.EntitySetName, product);

            }
        }context.SaveChanges();

Конечно, это выглядит неприлично. Я думаю, что причина в том, что отношения EF имеют статус сущностей (изменен, добавлен, удален), и на основании этого состояния EF изменяет значение внешних ключей или удаляет строку, если имеется отношение многие ко многим. По какой-то причине (не знаю почему) статус отношений не изменяется так же, как статус свойства. Вот почему я должен был установить CategoryReference.EntityKey для originalItem, чтобы изменить статус отношения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...