Pergunta

Eu tenho o seguinte cenário:

  1. As entidades são carregados a partir do banco de dados.
  2. Uma delas é apresentada ao usuário em um formulário (a WPF UserControl) onde o usuário pode editar propriedades daquela entidade.
  3. O usuário pode decidir aplicar as alterações para a entidade ou para cancelar a edição.

Como eu poderia implementar algo como isso com o EntityFramework?

Meu problema é que, quando eu ligar a interface do usuário diretamente para as propriedades da entidade, cada mudança é instantanously aplicado à entidade. Quero adiar isso para o momento em que o usuário pressionar OK ea entidade é validado com sucesso.

Eu pensei sobre como carregar as Entidades com NoTracking e chamando ApplyPropertyChanges depois de a entidade destacada foi validado, mas eu não estou totalmente certo sobre a maneira correta de fazer isso. O docu do EntityFramework no MSDN é muito escassa.

Outra maneira que eu poderia pensar é Refresh a entidade com StoreWins, mas eu não gosto de redefinir as mudanças em Cancelar em vez de aplicar as alterações em Ok.

Alguém tem um bom tutorial ou amostra?

Foi útil?

Solução

Um opções é o que você disse para fazer uma consulta de seguimento não.

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

Em seguida, o cliente pode modificar 'customer' conforme exigido na memória, e nada está realmente acontecendo no contexto.

Agora, quando você quer realmente fazer a mudança que você pode fazer isso:

// 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();

Agora, se você está desconfortável com a consulta, quer por razões de desempenho ou de simultaneidade, você pode adicionar um novo método de extensão AttachAsModified (...) para ObjectContext.

que é algo como isto:

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);
    }
}

Agora você pode escrever código como este:

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

E agora você não tem concorrência ou consultas extranous.

O único problema agora é lidar com propriedades FK. Você provavelmente deve olhar para o meu índice de dicas para ajuda aqui: http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx

Espero que isso ajude

Alex

Outras dicas

Eu sugiro IEditableObject, também, e, adicionalmente, IDataErrorInfo.

O que eu faço é, eu basicamente ter uma viewmodel para uma entidade que leva a entidade como parâmetro de construtor (basicamente um objeto wrapper).

Em BeginEdit, eu copiar as propriedades da entidade ao meu viewmodel, por isso, se eu faço CancelEdit, os dados são só mudou no ViewModel e da Entidade original não mudou. Em EndEdit, eu só aplicar as propriedades ViewModel à Entidade de novo, ou curso somente se a validação foi bem sucedida.

Para a validação i usar os métodos de IDataErrorInfo. Eu só implementar IDataErrorInfo.Error para que ele verifica o nome de cada propriedade via IDataErrorInfo [string columnName] e concatena eventuais mensagens de erro. Se ele está vazio, tudo é ok. (Não sei se erro é feito para ser usado dessa maneira, mas eu faço isso)

Se eu tiver outras Entidades ligadas à minha Entidade original, como Customer.Orders, eu criá-los como ViewModels aninhados no original ViewModel da Entidade. O ViewModel original pede iní-, Cancel-, EndEdit métodos É submodelos / erro em sua próprias implementações desses métodos então.

É um trabalho pouco mais, mas eu acho que vale a pena porque entre BeginEdit e EndEdit, você pode ter certeza de que nada muda sem você perceber. E ter um trecho de código para propriedades INotifyPropertyChanged habilitados ajuda muito também.

A maneira normal de fazer isto é vinculativo para algo que implementa IEditableObject . Se e como que se encaixa com a estrutura de entidade, não tenho certeza.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top