0

Je tente d'insérer/mettre à jour une entité en toute sécurité à l'aide d'Entity Framework 6. Au lieu d'utiliser la méthode AddOrUpdate qui n'est pas thread-safe et non recommandée pour Production, je pensais d'abord insérer l'entité dans ma DB. cela échoue en raison d'une collision Clé primaire, puis je fais une mise à jour à la place. J'ai utilisé le premier modèle de la base de données. Mon entité est un utilisateur dont la clé primaire = UserID et tous les autres champs sont nullables. J'ai besoin du scénario de mise à jour pour renvoyer l'entité mise à jour où les valeurs POST'ed sur les valeurs correspondantes en laissant tous les autres comme est dans la DB.Comment insérer/mettre à jour de manière sûre et efficace des enregistrements dans Entity Framework 6 pour les champs modifiés uniquement?

Par exemple, mon entité Utilisateur a 20 propriétés. Mon POST peut uniquement mettre à jour un petit sous-ensemble de ces propriétés pour un ID utilisateur donné. J'ai besoin de l'utilisateur retourné pour montrer l'utilisateur mis à jour.

Par exemple, je d'abord faire un POST pour insérer un nouvel utilisateur dont UserID = x1 comme ceci:

{ "UserID": "x1", "FirstName": "Utilisateur Prénom", "LastName": "Nom utilisateur", "E-mail": "[email protected]" }

Mon 2ème POST est une mise à jour pour que l'utilisateur de mettre à jour leur e-mail comme ceci:

{ "UserID": "x1", "Email ":" [email protected] " }

J'ai besoin du 2ème POST pour me montrer l'original FirstName et LastName I définis dans le premier Insert POST non NULL. Je vois l'original FirstName et LastName dans la base de données mais il n'apparaît pas dans la réponse du 2ème POST.

Les questions sont: (1) Qu'est-ce que je fais mal ici? (2) Je fais 2-3 requêtes à la DB. Existe-t-il un moyen plus simple de réduire les allers-retours à la base de données sans compromettre la sécurité des threads et la simultanéité?

private UCBContext db = new UCBContext(); 
    private bool InsertUser(ref User user) 
    { 
     try 
     { 
      db.Users.Add(user); 
      db.SaveChanges(); 
      return (true); 
     } 
     catch { } 
     return (false); 
    } 

    private bool UpdateUser(ref User user) 
    { 
     try 
     { 
      db.Users.Attach(user); 
      DbEntityEntry entry = db.Entry(user); 

      foreach (var propertyName in entry.CurrentValues.PropertyNames) 
      { 
       var value = entry.CurrentValues[propertyName]; 
       entry.Property(propertyName).IsModified = (propertyName != "UserID" && value != null); 
      } 

      db.SaveChanges(); 
      return (true); 
     } 
     catch { } 
     return (false); 
    } 

    // POST: api/users = Insert/Update User 
    [ResponseType(typeof(User))] 
    public IHttpActionResult PostUser(User user) 
    { 
     if (!ModelState.IsValid){ return BadRequest(ModelState); } 

     bool ok = InsertUser(ref user); 
     if (!ok) { ok = UpdateUser(ref user); } 

     User dbuser = db.Users.Find(user.UserID); 
     if(dbuser == null) { return NotFound(); } 

     return Ok(dbuser); 
    } 

public partial class User 
{ 
    public User() 
    { 
     this.Logins = 0; 
    } 

    public string UserID { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
    public Nullable<int> Logins { get; set; } 
} 
+0

D'où provient l'élément 'db'? –

+0

@ErikPhilips: J'avais ignoré la définition de db. Ajouté ci-dessus pour l'exhaustivité. Des idées? –

+0

Pouvez-vous partager votre classe de modèle - est l'ID utilisateur l'identifiant unique? – wazdev

Répondre

0

La dernière ligne retourne l'objet utilisateur d'origine ... vous devez faire:

return Ok(dbuser); 

au lieu de:

return Ok(user); 

Juste pour ajouter un peu plus de couleur à this- N'oubliez pas que lorsque vous passez l'objet utilisateur à InsertUser ou UpdateUser, vous en transmettez une copie. C'est pourquoi vous devez recharger en fonction de l'ID utilisateur, puis renvoyer cet objet utilisateur actualisé.

+0

J'ai mis à jour mon message avec le code que vous avez proposé. Cela n'a pas résolu le problème. Des idées? –

0

Voici une approche légèrement différente. Je n'ai pas testé ce code. Faites-nous savoir si cela ne fonctionne pas.

try 
    { 
     var existingUser = db.Users.Find(user.UserId); //or use db.Users.FirstOrDefault(...) 
     if(existingUser == null) 
     { 
      return false; 
     }     

     Type nType = user.GetType(); 
     PropertyInfo[] newValues = nType.GetProperties(); 

     foreach (PropertyInfo prop in newValues) 
     { 
      var propVal = prop.GetValue(user,null); 
      if(propVal!= null) 
      { 
       var eProp = existingUser.GetType().GetProperty(prop.Name); 
       if(eProp != null) 
       { 
        eProp.SetValue(existingUser, propVal, null); 
       } 
      }    
     }   
     db.SaveChanges(); 
     return (true); 
    } 
    catch { } 
    return (false); 
+0

J'ai ajouté la clause else mais cela n'a pas résolu le problème. Des idées s'il vous plaît? –

+0

Avez-vous essayé d'ajouter un point d'arrêt à 'if (value! = Null)' voir si la valeur est en fait 'null' ou quelque chose d'autre? –

+0

S'il vous plaît ne faites pas une déclaration if ... il peut simplement être réduit à 'entry.Property (propertyName) .IsModified = valeur! = Null;' –