EF4 / WCF SaveChanges () Meilleure pratique

entity-framework savechanges self-tracking-entities wcf

Question

C'est ainsi que nous implémentons un service générique Save () dans WCF pour nos entités EF. Un TT fait le travail pour nous. Même si cela ne nous pose aucun problème, je déteste supposer que c’est la meilleure approche (même si elle le pourrait). Vous avez l'air très vif et utile, alors j'ai pensé poser la question:

Y a-t-il un meilleur moyen?

[OperationContract]
public User SaveUser(User entity)
{
    bool _IsDeleted = false;
    using (DatabaseEntities _Context = new DatabaseEntities())
    {
        switch (entity.ChangeTracker.State)
        {
            case ObjectState.Deleted:
                //delete
                _IsDeleted = true;
                _Context.Users.Attach(entity);
                _Context.DeleteObject(entity);
                break;
            default:
                //everything else
                _Context.Users.ApplyChanges(entity);
                break;
        }
        // now, to the database
        try
        {
            // try to save changes, which may cause a conflict.
            _Context.SaveChanges(System.Data.Objects.SaveOptions.None);
        }
        catch (System.Data.OptimisticConcurrencyException)
        {
            // resolve the concurrency conflict by refreshing 
            _Context.Refresh(System.Data.Objects.RefreshMode.ClientWins, entity);
            // Save changes.
            _Context.SaveChanges();
        }
    }
    // return
    if (_IsDeleted)
        return null;
    entity.AcceptChanges();
    return entity;
}

Réponse acceptée

Pourquoi faites-vous cela avec les entités de suivi automatique? Quel était le problème avec ceci:

[OperationContract]
public User SaveUser(User entity)
{
    bool isDeleted = false;
    using (DatabaseEntities context = new DatabaseEntities())
    {
        isDeleted = entity.ChangeTracker.State == ObjectState.Deleted;
        context.Users.ApplyChanges(entity); // It deletes entities marked for deletion as well

        try
        {
            // no need to postpone accepting changes, they will not be accepted if exception happens
            context.SaveChanges(); 
        }
        catch (System.Data.OptimisticConcurrencyException)
        {
            context.Refresh(System.Data.Objects.RefreshMode.ClientWins, entity);
            context.SaveChanges();
        }
    }

    return isDeleted ? null : entity;
}

Réponse populaire

Si je ne me trompe pas, les gens n'exposent généralement pas leurs objets Entity Framework directement dans un service WCF. Entity Framework est généralement considéré comme une couche d'accès aux données, et WCF étant davantage une couche frontale, elles sont donc placées à différents niveaux.

Un objet de transfert de données (DTO) est utilisé dans les méthodes WCF. Il s'agit généralement d'un POCO qui ne comporte aucun suivi d'état. Le DTO est ensuite mappé sur une entité manuellement ou via un framework tel qu'AutoMapper.

En général, les clients doivent savoir s’ils «ajoutent» ou «mettent à jour» un objet, et je préférerais personnellement que ces opérations soient deux opérations distinctes sur l’interface de service. En outre, je leur demanderais certainement d'utiliser une méthode distincte pour supprimer un objet. Cependant, si vous avez absolument besoin d'une "Sauvegarde" générique, vous devriez être capable de dire si l'objet qui vous a été fourni est "nouveau" ou non en fonction de la présence (ou de l'absence) d'une valeur de clé primaire.

Une grande partie du code peut être insérée dans un utilitaire générique. Par exemple, en supposant que votre modèle T4 génère des attributs sur les valeurs de clé de vos entités, vous pouvez déterminer automatiquement si les valeurs de clé sont présentes et effectuer une insertion / mise à jour en conséquence. En outre, le bloc de try SaveChanges catch retry que vous utilisez - bien qu’il soit probablement inutile - pourrait facilement être intégré à une méthode utilitaire simple afin d’être plus DRY.



Related

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