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 Blog
foi criado e sua UserId
propriedade está definida corretamente. No entanto, a BlogId
propriedade 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.
Se um usuário só pode ter um blog, então um relacionamento um-para-um clássico seria assim:
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:
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:
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.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.