Question

J'ai le scénario suivant:

  1. Les entités sont chargées à partir de la base de données.
  2. L'un d'eux est présenté à l'utilisateur dans un formulaire (un contrôle utilisateur WPF) dans lequel l'utilisateur peut modifier les propriétés de cette entité.
  3. L'utilisateur peut décider d'appliquer les modifications à l'entité ou d'annuler la modification.

Comment pourrais-je implémenter quelque chose comme ceci avec EntityFramework?

Mon problème est que, lorsque je lie l'interface utilisateur directement aux propriétés de l'entité, chaque modification est appliquée instantanément à l'entité. Je souhaite reporter cela au moment où l'utilisateur appuie sur OK et que l'entité est validée avec succès.

J'ai pensé charger les entités avec NoTracking et appeler ApplyPropertyChanges une fois que l'entité détachée a été validée, mais je ne suis pas tout à fait sûr de la bonne façon de procéder. . Le document de l'EntityFramework chez MSDN est très clairsemé.

Je pourrais aussi penser à Actualiser de l'entité avec StoreWins , mais je n'aime pas réinitialiser les modifications à Annuler au lieu d'appliquer les modifications à Ok.

Quelqu'un at-il un bon tutoriel ou un bon échantillon?

Était-ce utile?

La solution

Une des options est ce que vous avez dit de faire une requête sans suivi.

ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First(c => c.ID == 232);

Ensuite, le client peut modifier 'client' selon les besoins en mémoire et rien ne se passe réellement dans le contexte.

Maintenant, quand vous voulez réellement apporter le changement, vous pouvez le faire:

// get the value from the database
var original = ctx.Customers.First(c => c.ID == customer.ID);
// copy values from the changed entity onto the original.
ctx.ApplyPropertyChanges(customer); .
ctx.SaveChanges();

Maintenant, si la requête vous met mal à l'aise pour des raisons de performances ou de concurrence, vous pouvez ajouter une nouvelle méthode d'extension AttachAsModified (...) à ObjectContext.

qui ressemble à ceci:

public static void AttachAsModified<T>(
    this ObjectContext ctx, 
    string entitySet, 
    T entity)
{
    ctx.AttachTo(entitySet, entity);

    ObjectStateEntry entry = 
            ctx.ObjectStateManager.GetObjectStateEntry(entity);

    // get all the property names
    var propertyNames = 
            from s in entry.CurrentValues.DataRecordInfo.FieldMetadata
            select s.FieldType.Name;

    // mark every property as modified    
    foreach(var propertyName in propertyNames)
    {
        entry.SetModifiedProperty(propertyName);
    }
}

Vous pouvez maintenant écrire du code comme ceci:

ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First();
// make changes to the customer in the form
ctx.AttachAsModified("Customers", customer);
ctx.SaveChanges();

Et maintenant, vous n'avez plus de requêtes d'accès simultané ou extranous.

Le seul problème concerne les propriétés FK. Vous devriez probablement consulter mon index de conseils d’aide ici: http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx

J'espère que cela vous aidera

Alex

Autres conseils

Je suggère également IEditableObject et IDataErrorInfo.

Comme je le fais, j’ai essentiellement un modèle de vue pour une entité qui prend l’entité en tant que paramètre constructeur (essentiellement un objet wrapper).

Dans BeginEdit, je copie les propriétés de l'entité dans mon modèle de vue. Par conséquent, si je supprime CancelEdit, les données ne sont modifiées que dans le ViewModel et l'entité d'origine n'a pas changé. Dans EndEdit, je réapplique simplement les propriétés ViewModel à l'entité, ou bien sûr uniquement si la validation a réussi.

Pour la validation, j'utilise les méthodes de IDataErrorInfo. Je viens d'implémenter IDataErrorInfo.Error pour qu'il vérifie chaque nom de propriété via IDataErrorInfo [chaîne nomcolonne] et concatène les éventuels messages d'erreur. Si c'est vide, tout va bien. (Je ne sais pas si Error doit être utilisé de cette façon, mais je le fais.)

Si d'autres entités sont associées à mon entité d'origine, telles que Customer.Orders, je les crée en tant que ViewModels imbriqués dans le ViewModel de l'entité d'origine. Le ViewModel d'origine appelle ses méthodes Begin-, Cancel-, EndEdit / Error de ses sous-modèles dans ses propres implémentations de ces méthodes, puis.

C'est un peu plus de travail, mais je pense que cela en vaut la peine, car entre BeginEdit et EndEdit, vous pouvez être presque certain que rien ne change sans que vous le remarquiez. Et avoir un extrait de code pour les propriétés activées par INotifyPropertyChanged aide également beaucoup.

La manière habituelle de faire cela est de lier quelque chose qui implémente IEditableObject . Si et comment cela s’intègre dans le cadre des entités, je ne suis pas sûr.

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