As duas entidades são um-para-muitos relacionamento (construído pelo código primeiro API fluente).
public class Parent
{
public Parent()
{
this.Children = new List<Child>();
}
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
}
No meu controlador WebApi, tenho ações para criar uma entidade pai (que está funcionando bem) e atualizar uma entidade pai (que tem algum problema). A ação de atualização é semelhante a:
public void Update(UpdateParentModel model)
{
//what should be done here?
}
Atualmente, tenho duas idéias:
Obtenha uma entidade pai rastreada nomeada
existing
pormodel.Id
e atribua valoresmodel
um a um à entidade. Isso parece estúpido. Emodel.Children
não sei qual filho é novo, qual filho é modificado (ou mesmo excluído).Crie uma nova entidade pai via
model
e anexe-a ao DbContext e salve-a. Mas como o DbContext pode conhecer o estado dos filhos (nova adição / exclusão / modificação)?
Qual é a maneira correta de implementar esse recurso?
c#
asp.net-mvc
entity-framework
asp.net-web-api
Cheng Chen
fonte
fonte
Respostas:
Como o modelo que é lançado no controlador WebApi é desanexado de qualquer contexto de entidade-estrutura (EF), a única opção é carregar o gráfico de objeto (pai, incluindo seus filhos) do banco de dados e comparar quais filhos foram adicionados, excluídos ou Atualizada. (A menos que você rastreie as alterações com seu próprio mecanismo de rastreamento durante o estado desanexado (no navegador ou em qualquer outro local) que, na minha opinião, seja mais complexo do que o seguinte).
...CurrentValues.SetValues
pode levar qualquer objeto e mapear valores de propriedade para a entidade anexada com base no nome da propriedade. Se os nomes de propriedades em seu modelo forem diferentes dos nomes na entidade, você não poderá usar este método e deverá atribuir os valores um a um.fonte
existingParent.Children.Add(newChild)
porque a pesquisa linq existente do Child retornará a entidade adicionada recentemente e, portanto, a entidade será atualizada. Você só precisa inserir em uma lista temporária e adicionar.existingChild
consulta LINQ:.Where(c => c.ID == childModel.ID && c.ID != default(int))
Eu tenho mexido com algo assim ...
que você pode chamar com algo como:
Infelizmente, isso meio que cai se houver propriedades de coleção no tipo filho que também precisam ser atualizadas. Considere tentar resolver isso passando um IRepository (com métodos básicos de CRUD) que seria responsável por chamar UpdateChildCollection por conta própria. Chamaria o repo em vez de chamadas diretas para DbContext.Entry.
Não tenho idéia de como tudo isso funcionará em escala, mas não tenho certeza do que mais fazer com esse problema.
fonte
toAdd.ForEach(i => (selector(dbItem) as ICollection<Tchild>).Add(i.Value));
deve resolver o problema n -> n.Ok pessoal. Eu tive essa resposta uma vez, mas a perdi no caminho. tortura absoluta quando você sabe que há uma maneira melhor, mas não consegue se lembrar ou encontrar! É muito simples. Eu apenas testei de várias maneiras.
Você pode substituir a lista inteira por uma nova! O código SQL removerá e adicionará entidades conforme necessário. Não há necessidade de se preocupar com isso. Certifique-se de incluir a coleção infantil ou nenhum dado. Boa sorte!
fonte
Se você estiver usando EntityFrameworkCore, poderá fazer o seguinte na ação pós-controlador (o método Attach anexa recursivamente as propriedades de navegação, incluindo coleções):
Supõe-se que cada entidade que foi atualizada possui todas as propriedades definidas e fornecidas nos dados de postagem do cliente (por exemplo, não funcionará para atualização parcial de uma entidade).
Você também precisa certificar-se de estar usando um contexto de banco de dados de estrutura de entidade novo / dedicado para esta operação.
fonte
Foi assim que resolvi esse problema. Dessa forma, a EF sabe qual adicionar e quais atualizar.
fonte
Existem alguns projetos por aí que facilitam a interação entre o cliente e o servidor no que diz respeito a salvar um gráfico inteiro de objetos.
Aqui estão dois que você gostaria de ver:
Os dois projetos acima reconhecem as entidades desconectadas quando retornadas ao servidor, detectam e salvam as alterações e retornam aos dados afetados pelo cliente.
fonte
Apenas a prova de conceito
Controler.UpdateModel
não funcionará corretamente.Classe completa aqui :
fonte
@ Charles McIntosh realmente me deu a resposta para minha situação, pois o modelo passado foi desanexado. Para mim, o que funcionou foi salvar primeiro o modelo passado ... depois continuar adicionando os filhos como eu já era antes:
fonte
Para desenvolvedores do VB.NET Use essa sub genérica para marcar o estado filho, fácil de usar
fonte
fonte
fonte
Aqui está o meu código que funciona muito bem.
fonte