Question

J'utilise EF pour essayer de mettre à jour une entité avec ASP.NET. Je crée une entité, en définissant les propriétés, puis en la renvoyant à l'EF sur un calque distinct avec l'ID afin que la modification puisse être appliquée. Je le fais parce que je ne stocke que l'ID de l'entité lorsqu'elle a été liée aux contrôles de l'interface utilisateur.

Tout fonctionne pour les propriétés standard, mais je ne peux pas mettre à jour l'ID de catégorie d'un produit (une entité liée). J'ai essayé EntityKey, EntityReference et quelques autres, mais l'ID de catégorie n'est pas enregistré. Voici ce que j'ai:

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();
 }
}

Je souhaite vraiment utiliser l'EF, mais il semble que je rencontre quelques problèmes d'utilisation avec ASP.NET.

Était-ce utile?

La solution

Ceci est une réponse acceptée à cette question ASP.NET fortement typé MVC avec Entity Framework

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

Avez-vous essayé cela?

[Mise à jour, le code sur le dessus ne fonctionne pas]

Ceci est une petite propriété d'extension que j'ai utilisée afin que le bloc de code suivant soit plus facile à comprendre:

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;
        }
    }
}

et cela a fonctionné pour moi (cette fois, c'est sûr):

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();

Bien sûr, ça a l'air hacky. Je pense que la raison en est que les relations EF ont le statut d’entités (modifiées, ajoutées, supprimées) et qu’en fonction de ce statut, EF change la valeur des clés étrangères ou supprime la ligne si la relation plusieurs à plusieurs est la casse. Pour une raison quelconque (je ne sais pas pourquoi), le statut de la relation n'est pas modifié de la même manière que le statut de la propriété. C'est pourquoi j'ai dû définir CategoryReference.EntityKey sur originalItem afin de modifier le statut de la relation.

Autres conseils

La raison de cet échec est double.

  1. Pour mettre à jour une référence (c'est-à-dire Product.Category), vous devez également avoir la valeur de référence d'origine dans le contexte.
  2. ApplyPropertyChanges (...) s'applique uniquement aux propriétés régulières / scalaires de l'entité, la référence n'est pas modifiée

Je ferais donc quelque chose comme ceci (Notez que ce code utilise beaucoup une astuce appelée les entités stub pour éviter de se fourvoyer avec 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();
 }
}

Cela fera le travail, en supposant qu'aucune faute de frappe, etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top