使用Entity Framework插入主实体时依赖实体未入库问题
问题背景
首先,实体类定义如下:
public class Restaurant : Entity { public string Name { get; set; } public int OwnerId { get; set; } public virtual Owner Owner { get; set; } public virtual Menu Menu { get; set; } public Restaurant() { Menu = new Menu(); } } public class Menu : Entity { public int RestaurantId { get; set; } public virtual ICollection<Campaign> Campaigns { get; set; } public virtual ICollection<Category> Categories { get; set; } public virtual Restaurant Resturant { get; set; } public Menu() { Campaigns = new HashSet<Campaign>(); Categories = new HashSet<Category>(); } }
它们之间为一对一关系,配置如下:
modelBuilder.Entity<Restaurant>(r => { r.HasOne(r => r.Owner) .WithMany() .HasForeignKey(r =>r.OwnerId); r.HasOne(r => r.Menu) .WithOne(m => m.Resturant) .HasForeignKey<Menu>(m => m.RestaurantId); }); modelBuilder.Entity<Menu>(m => { m.HasMany(m => m.Campaigns) .WithOne(c => c.Menu) .HasForeignKey(x => x.MenuId); m.HasMany(m => m.Categories) .WithOne(c => c.Menu) .HasForeignKey(c => c.MenuId); m.HasOne(m => m.Resturant) .WithOne(r => r.Menu); });
问题描述
处理CreateRestaurantCommand请求创建Restaurant时,代码逻辑如下:
public class CreateRestaurantCommandHandler : IRequestHandler<CreateRestaurantCommand, CreatedRestaurantResponseDto> { private readonly IRestaurantRepository _restaurantRepository; private readonly RestaurantBusinessRules _restaurantBusinessRules; public CreateRestaurantCommandHandler(IRestaurantRepository restaurantRepository, RestaurantBusinessRules restaurantBusinessRules) { _restaurantRepository = restaurantRepository; _restaurantBusinessRules = restaurantBusinessRules; } public async Task<CreatedRestaurantResponseDto> Handle(CreateRestaurantCommand request, CancellationToken cancellationToken) { await _restaurantBusinessRules.DoesOwnerExistAndHaveRestaurantWithSameName(request.OwnerId, request.RestaurantName); Restaurant restaurant = new() { Name = request.RestaurantName, OwnerId = request.OwnerId, }; Restaurant createdRestaurant = await _restaurantRepository.CreateAsync(restaurant); CreatedRestaurantResponseDto response = new() { Id = createdRestaurant.Id, Name = createdRestaurant.Name, OwnerId = createdRestaurant.OwnerId }; return response; } }
Restaurant创建正常,但构造函数中初始化的Menu未插入数据库。CreateAsync方法实现如下:
public async Task<TEntity> CreateAsync(TEntity entity) { Context.Entry(entity).State = EntityState.Added; await Context.SaveChangesAsync(); return entity; }
尝试过空构造函数初始化Menu、修改DbContext配置,均未解决问题。
解决方案
1. 替换手动状态设置为Add方法(推荐)
手动设置EntityState.Added只会标记当前实体,EF Core不会自动处理关联的导航属性。改用Context.Set<TEntity>().Add(entity),EF会自动遍历实体图,将关联的Menu也标记为Added:
public async Task<TEntity> CreateAsync(TEntity entity) { Context.Set<TEntity>().Add(entity); await Context.SaveChangesAsync(); return entity; }
2. 修正导航属性拼写错误
Menu类中的Resturant拼写错误(应为Restaurant),会导致EF无法正确识别关联关系,修正后同步更新Fluent配置:
// Menu类修正 public virtual Restaurant Restaurant { get; set; } // Fluent配置修正 modelBuilder.Entity<Restaurant>(r => { r.HasOne(r => r.Menu) .WithOne(m => m.Restaurant) // 同步修正 .HasForeignKey<Menu>(m => m.RestaurantId); }); modelBuilder.Entity<Menu>(m => { m.HasOne(m => m.Restaurant) // 同步修正 .WithOne(r => r.Menu); });
3. 手动标记Menu为Added(备选)
如果必须保留手动设置状态的逻辑,需同时标记Menu并设置外键:
public async Task<TEntity> CreateAsync(TEntity entity) { Context.Entry(entity).State = EntityState.Added; if (entity is Restaurant restaurant && restaurant.Menu != null) { Context.Entry(restaurant.Menu).State = EntityState.Added; restaurant.Menu.RestaurantId = restaurant.Id; } await Context.SaveChangesAsync(); return entity; }
内容的提问来源于stack exchange,提问作者ashwor11
相关产品推荐
相关产品推荐

