Mise à jour de l'entité Framework avec l'entité associée

asp.net entity-framework foreign-keys

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 stocke uniquement 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 le Category.ID 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 EF, mais il semble que je rencontre quelques problèmes d’utilisation avec ASP.NET.

Réponse acceptée

Ceci est accepté. Réponse à cette question ASP.NET MVC fortement typé 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?

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

C'est une petite propriété d'extension que j'ai utilisée, donc le bloc de code suivant est 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 à coup 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 modifie la valeur des clés étrangères ou supprime la ligne si la relation plusieurs à plusieurs est le cas. 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.


Réponse populaire

La raison pour laquelle cela échoue 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 entités de bout pour éviter de se faufiler 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 pas de fautes de frappe, etc.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow