Quando salvo uma entidade com estrutura de entidade, naturalmente assumi que só tentaria salvar a entidade especificada. No entanto, ele também está tentando salvar as entidades filhas dessa entidade. Isso está causando todos os tipos de problemas de integridade. Como faço para forçar o EF a salvar apenas a entidade que desejo salvar e, portanto, ignorar todos os objetos filho?
Se eu definir manualmente as propriedades como nulas, recebo um erro "A operação falhou: o relacionamento não pôde ser alterado porque uma ou mais propriedades de chave estrangeira não podem ser anuladas." Isso é extremamente contraproducente, pois eu defini o objeto filho como nulo especificamente para que o EF o deixasse sozinho.
Por que não quero salvar / inserir os objetos filho?
Uma vez que isso está sendo discutido continuamente nos comentários, darei algumas justificativas de porque quero que meus objetos filhos sejam deixados sozinhos.
No aplicativo que estou construindo, o modelo de objeto EF não está sendo carregado do banco de dados, mas usado como objetos de dados que estou preenchendo ao analisar um arquivo simples. No caso dos objetos filho, muitos deles se referem a tabelas de pesquisa que definem várias propriedades da tabela pai. Por exemplo, a localização geográfica da entidade primária.
Já que eu mesmo povoei esses objetos, EF assume que esses são novos objetos e precisam ser inseridos junto com o objeto pai. No entanto, essas definições já existem e não quero criar duplicatas no banco de dados. Eu só uso o objeto EF para fazer uma pesquisa e preencher a chave estrangeira na minha entidade de tabela principal.
Mesmo com os objetos filhos que são dados reais, eu preciso salvar o pai primeiro e obter uma chave primária ou o EF parece bagunçar as coisas. Espero que isso dê alguma explicação.
fonte
Respostas:
Pelo que eu sei, você tem duas opções.
Opção 1)
Anular todos os objetos filho, isso irá garantir que EF não adicione nada. Ele também não excluirá nada do seu banco de dados.
Opção 2)
Defina os objetos filho como separados do contexto usando o código a seguir
Observe que você não pode desanexar um
List
/Collection
. Você terá que fazer um loop em sua lista e destacar cada item de sua lista assimfonte
Resumindo: use a chave estrangeira e isso salvará o seu dia.
Suponha que você tenha uma entidade Escola e uma entidade Cidade , e esse é um relacionamento muitos para um em que uma cidade tem muitas escolas e uma Escola pertence a uma cidade. E suponha que as cidades já existam na tabela de pesquisa, então você NÃO deseja que elas sejam inseridas novamente ao inserir uma nova escola.
Inicialmente, você pode definir suas entidades assim:
E você pode fazer a inserção School assim (suponha que você já tenha a propriedade City atribuída ao newItem ):
A abordagem acima pode funcionar perfeitamente neste caso, entretanto, eu prefiro a abordagem de chave estrangeira , que para mim é mais clara e flexível. Veja a solução atualizada abaixo:
Desta forma, você define explicitamente que a escola tem uma chave estrangeira City_Id e se refere à entidade City . Então, quando se trata de inserção de Escola , você pode fazer:
Nesse caso, você especifica explicitamente o City_Id do novo registro e remove a cidade do gráfico para que EF não se preocupe em adicioná-lo ao contexto junto com Escola .
Embora à primeira impressão a abordagem da chave estrangeira pareça mais complicada, mas acredite em mim, essa mentalidade vai lhe poupar muito tempo quando se trata de inserir um relacionamento muitos para muitos (imaginando que você tem um relacionamento Escola e Aluno, e o Aluno tem uma propriedade City) e assim por diante.
Espero que este seja útil para você.
fonte
[Range(1, int.MaxValue)]
atributo?Se você deseja apenas armazenar alterações em um objeto pai e evitar o armazenamento de alterações em qualquer um de seus objetos filho , por que não fazer o seguinte:
A primeira linha anexa o objeto pai e todo o gráfico de seus objetos filhos dependentes ao contexto no
Unchanged
estado.A segunda linha muda o estado apenas para o objeto pai, deixando seus filhos no
Unchanged
estado.Observe que eu uso um contexto recém-criado, portanto, isso evita salvar quaisquer outras alterações no banco de dados.
fonte
Uma das soluções sugeridas é atribuir a propriedade de navegação do mesmo contexto de banco de dados. Nesta solução, a propriedade de navegação atribuída de fora do contexto do banco de dados seria substituída. Por favor, veja o exemplo a seguir para ilustração.
Salvando no banco de dados:
A Microsoft considera isso um recurso, mas acho isso irritante. Se o objeto departamento associado ao objeto da empresa possui um Id que já existe no banco de dados, então por que EF não associa apenas o objeto da empresa ao objeto do banco de dados? Por que devemos cuidar da associação sozinhos? Cuidar da propriedade de navegação durante a adição de um novo objeto é algo como mover as operações do banco de dados de SQL para C #, complicado para os desenvolvedores.
fonte
Primeiro você precisa saber que existem duas maneiras de atualizar a entidade no EF.
No aplicativo que estou construindo, o modelo de objeto EF não está sendo carregado do banco de dados, mas usado como objetos de dados que estou preenchendo ao analisar um arquivo simples.
Isso significa que você está trabalhando com um objeto desconectado, mas não está claro se você está usando uma associação independente ou uma associação de chave estrangeira .
Adicionar
Ao adicionar uma nova entidade com um objeto filho existente (objeto que existe no banco de dados), se o objeto filho não for rastreado por EF, o objeto filho será reinserido. A menos que você anexe manualmente o objeto filho primeiro.
Atualizar
Você pode apenas marcar a entidade como modificada, então todas as propriedades escalares serão atualizadas e as propriedades de navegação serão simplesmente ignoradas.
Gráfico Diff
Se você deseja simplificar o código ao trabalhar com um objeto desconectado, você pode tentar criar uma biblioteca de diff em gráfico .
Aqui está a introdução, Apresentando GraphDiff para Entity Framework Code First - permitindo atualizações automatizadas de um gráfico de entidades desanexadas .
Código de amostra
Insira a entidade se ela não existir, caso contrário, atualize.
Insira a entidade se ela não existir, caso contrário, atualize E insira o objeto filho se ele não existir, caso contrário atualize.
fonte
A melhor maneira de fazer isso é substituindo a função SaveChanges em seu texto de dados.
fonte
Estou com o mesmo problema quando tento salvar perfil, já tabela saudação e novidade para criar perfil. Quando eu insiro o perfil, ele também insere na saudação. Então eu tentei assim antes de savechanges ().
db.Entry (Profile.Salutation) .State = EntityState.Unchanged;
fonte
Isso funcionou para mim:
fonte
O que fizemos é antes de adicionar o pai ao dbset, desconectar as coleções filho do pai, certificando-se de enviar as coleções existentes para outras variáveis para permitir trabalhar com elas mais tarde, e então substituir as coleções filho atuais por novas coleções vazias. Definir as coleções filho como null / nothing pareceu falhar para nós. Depois de fazer isso, adicione o pai ao dbset. Dessa forma, os filhos não são adicionados até que você queira.
fonte
Eu sei que é um post antigo, no entanto, se você estiver usando a abordagem de código primeiro, você pode obter o resultado desejado usando o seguinte código em seu arquivo de mapeamento.
Isso basicamente dirá ao EF para excluir a propriedade "ChildObjectOrCollection" do modelo para que não seja mapeada para o banco de dados.
fonte
Eu tive um desafio semelhante ao usar o Entity Framework Core 3.1.0, minha lógica de repositório é bastante genérica.
Isso funcionou para mim:
Observe que "ParentEntityId" é o nome da coluna da chave estrangeira na entidade filha. Eu adicionei a linha de código mencionada acima neste método:
fonte