AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79591481
Accepted
dave
dave
Asked: 2025-04-25 05:27:07 +0800 CST2025-04-25 05:27:07 +0800 CST 2025-04-25 05:27:07 +0800 CST

O EF Core não mapeia chaves estrangeiras corretamente ao criar novas entidades

  • 772

Estou com problemas para criar novas entidades com relacionamentos um-para-um. O EF Core não está atribuindo as chaves estrangeiras corretamente.

Como exemplo, vamos pegar duas entidades:

public class User
{
    public int Id { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

public class Blog
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
}

Defina o relacionamento deles de modo que fique claro qual depende de qual:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<User>()
        .HasOne(u => u.Blog)
        .WithOne(b => b.User)
        .HasForeignKey<Blog>()
        .IsRequired();
}

Então, quando tento criá-los assim:

var user = new User 
               {
                   Blog = new Blog(),
               };

await DbContext.Set<User>().AddAsync(user);
await DbContext.SaveChangesAsync();

O Blogfoi criado e sua UserIdpropriedade está definida corretamente. No entanto, a BlogIdpropriedade de Useré 0. De acordo com a documentação , deve ser possível criar entidades relacionadas como esta.

Isso não se aplica a relacionamentos individuais? Ou há algo mais que não estou percebendo?

A propósito, estou usando o PostgreSQL, caso o provedor do banco de dados tenha algo a ver com isso. Também estou usando o EF Core versão 9.

postgresql
  • 2 2 respostas
  • 58 Views

2 respostas

  • Voted
  1. Best Answer
    Steve Py
    2025-04-25T09:19:59+08:002025-04-25T09:19:59+08:00

    Se um usuário só pode ter um blog, então um relacionamento um-para-um clássico seria assim:

    public class User
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public Blog Blog { get; set; }
    }
    public class Blog
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
        public User User { get; set; }
    }
    
    // with...
        builder.Entity<User>()
            .HasOne(u => u.Blog)
            .WithOne(b => b.User)
            .IsRequired();
    

    Por padrão, o EF associará ambas as entidades por suas PKs, não sendo necessário um FK separado em cada tabela. Em um relacionamento um para um, as duas tabelas compartilham o mesmo PK. Não faz sentido que elas tenham PKs diferentes, pois elas só existirão em pares. Você pode especificar um FK alternativo em qualquer uma das tabelas, mas apenas em uma ou na outra, e isso não é necessário, a menos que o relacionamento seja bidirecionalmente opcional. (Podemos ter relacionamentos 0-1, 1-1 ou 1-0 entre usuários e blogs). Nesse cenário, você deve usar um FK dedicado em uma ou nas outras tabelas.

    No entanto, neste exemplo, não faz sentido que um usuário tenha apenas um blog. É provável que ele tenha vários. Seria uma relação de um para muitos:

    public class User
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public ICollection<Blog> Blogs { get; } = [];
    }
    public class Blog
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public int UserId { get; set; }
        public User User { get; set; }
    }
    
    // with...
        builder.Entity<User>()
            .HasMany(u => u.Blogs)
            .WithOne(b => b.User)
            .HasForeignKey(b => b.UserId)
    

    Aqui podemos ter um registro de Usuário com 0 para qualquer número de blogs, e a criação de um Blog requer estar associado a um Usuário.

    Neste caso, eu recomendaria usar uma Shadow Property para o UserId FK na tabela Blog:

    public class User
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public ICollection<Blog> Blogs { get; } = [];
    }
    public class Blog
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public User User { get; set; }
    }
    
    // with...
        builder.Entity<User>()
            .HasMany(u => u.Blogs)
            .WithOne(b => b.User)
            .HasForeignKey("UserId")
    

    Isso informa ao EF que há uma coluna UserId na tabela Blogs para servir como FK para o Usuário sem expor uma propriedade UserId na entidade Blog. Quando se trata de referências bidirecionais, geralmente é melhor evitar expor as propriedades FK e de navegação, pois isso forma duas fontes de verdade. Se uma propriedade de navegação for carregada/definida, ela terá precedência sobre a propriedade FK, mas definir a propriedade FK quando a propriedade de navegação não estiver definida/carregada terá precedência. Isso pode levar a bugs se algum código verificar/depender de blog.UserId enquanto outro código pode usar blog.User. Definir a FK não altera nenhuma referência de Usuário carregada. Definir a propriedade de navegação não atualiza automaticamente a FK até que ela SaveChanges()seja chamada. Normalmente, é mais seguro usar uma ou outra e tenha cuidado se houver um motivo para usar ambas.

    • 2
  2. Weber K.
    2025-04-25T07:35:04+08:002025-04-25T07:35:04+08:00

    Recomendo fortemente o uso de engenharia reversa.

    O dbcontext é criado corretamente para você com todos os relacionamentos.

    Acho que você só precisa de um para ter um relacionamento individual;

    BlogId no usuário ou

    UserId no Blog

    Ter ambos cria redundância. Se você quiser, por exemplo, acelerar consultas reversas, sugiro definir o valor com um gatilho para evitar inconsistências.

    • 1

relate perguntas

  • Como usar jackc/pgx com pool de conexão, contexto, instruções preparadas etc.

  • Escreva uma consulta psql para localizar usuários em um intervalo de tempo

  • O caractere de escape de barra invertida do Postgresql não funciona para vírgulas em COPY FROM

  • biblioteca postgresql não encontrada no contêiner docker baseado em clojure

  • A inserção do Postgres está acontecendo apesar de violar a restrição de índice parcial

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve