6 votes

Code EF5 d'abord avec ASP.NET Web API : Mise à jour d'une entité avec une relation plusieurs à plusieurs

J'essaie de mettre à jour un Customer dans ma base de données en utilisant ASP.NET Web API et Entity Framework 5 code-first, mais cela ne fonctionne pas. Mes entités ressemblent à ceci :

public class CustomerModel
{
    public int Id { get; set; }
    public string Name { get; set; }

    // More fields

    public ICollection<CustomerTypeModel> CustomerTypes { get; set; }
}

public class CustomerTypeModel
{
    public int Id { get; set; }
    public string Type { get; set; }

    [JsonIgnore]
    public ICollection<CustomerModel> Customers { get; set; }
}

Rien d'extraordinaire. J'ai construit une interface web où les utilisateurs peuvent ajouter un client en fournissant le nom et en cochant un ou plusieurs types de clients. Lorsque l'utilisateur clique sur le bouton "submit", les données sont envoyées à ma méthode API Web :

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        context.Customers.Attach(customer);
        context.Entry(customer).State = EntityState.Modified;
        context.SaveChanges();
    }
}

Cette opération met à jour les champs du client, mais les types de clients associés sont ignorés. Les données customer contient bien une liste de CustomerTypes à laquelle elle doit être associée :

[0] => { Id: 1, Type: "Finance", Customers: Null },
[1] => { Id: 2, Type: "Insurance", Customers: Null }
[2] => { Id: 3, Type: "Electronics", Customers: Null }

Mais au lieu d'examiner cette liste et d'ajouter/supprimer les entités associées, EF l'ignore tout simplement. Les nouvelles associations sont ignorées et les associations existantes sont conservées même si elles devraient être supprimées.

J'ai rencontré un problème similaire lors de l'insertion d'un client dans la base de données, qui a été résolu lorsque j'ai ajusté l'état de ces entités à EntityState.Unchanged . Naturellement, j'ai essayé d'appliquer cette même solution magique dans mon scénario de mise à jour :

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        foreach (var customertype in customer.CustomerTypes)
        {
            context.Entry(customertype).State = EntityState.Unchanged;
        }

        context.Customers.Attach(customer);
        context.Entry(customer).State = EntityState.Modified;
        context.SaveChanges();
    }
}

Mais EF continue d'afficher le même comportement.

Des idées sur la façon de résoudre ce problème ? Ou dois-je vraiment faire un effacement manuel de la liste des CustomerTypes et de les ajouter manuellement ?

Merci d'avance.

JP

10voto

Slauma Points 76561

Il n'est pas vraiment possible de résoudre ce problème en se contentant de définir les états des entités. Vous devez d'abord charger le client à partir de la base de données, y compris tous ses types actuels, puis supprimer ou ajouter des types au client chargé en fonction de la collection de types mise à jour du client affiché. Le suivi des modifications se chargera de supprimer les entrées de la table de jointure ou d'en insérer de nouvelles :

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        var customerInDb = context.Customers.Include(c => c.CustomerTypes)
            .Single(c => c.Id == customer.Id);

        // Updates the Name property
        context.Entry(customerInDb).CurrentValues.SetValues(customer);

        // Remove types
        foreach (var typeInDb in customerInDb.CustomerTypes.ToList())
            if (!customer.CustomerTypes.Any(t => t.Id == typeInDb.Id))
                customerInDb.CustomerTypes.Remove(typeInDb);

        // Add new types
        foreach (var type in customer.CustomerTypes)
            if (!customerInDb.CustomerTypes.Any(t => t.Id == type.Id))
            {
                context.CustomerTypes.Attach(type);
                customerInDb.CustomerTypes.Add(type);
            }

        context.SaveChanges();
    }
}

0voto

boskop Points 31

Une solution plus propre serait la suivante :

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        var customerInDb = context.Customers.Include(c => c.CustomerTypes)
            .Single(c => c.Id == customer.Id);

        // Updates the Name property
        context.Entry(customerInDb).CurrentValues.SetValues(customer);

        // Remove types
        customer.CustomerTypes.Clear();

        // Add new types
        foreach (var type in customer.CustomerTypes) 
        {
            context.CustomerTypes.Attach(type);
            customerInDb.CustomerTypes.Add(type);
        }

        context.SaveChanges();
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X