远离我们上下文的EF6 DB第一个模型 - 我正在构建一个ASP核心API,它使用EF Core Code First模型用于数据库上下文。要在滚动更新中执行此操作,我的上下文必须与当前数据库模式一起存在,因此我使用EF Fluent API为不反映当前数据库模式的Code First模型构建实体映射。
我在插入操作期间遇到实体上导航属性的问题。使用标准.Include(x => x.OtherEntity)格式从数据库获取主数据的数据效果很好,将主实体保存回数据库是问题所在。
使用Fluent API来映射实体对我来说是新的,因此学习曲线很可能是我的问题所在。我曾尝试使用OwnsOne与HasOne,但MS文档表明HasOne()是执行此映射的正确方法。
当我在流畅映射中使用.HasOne()时,我的主要实体具有外键关键字字段的阴影属性(在下面的代码中)
在这种情况下,异常消息没有用,因为它们不反映映射问题,它们表明当导航属性的表具有标识列时,无法插入数据(IE无法插入带有显式的记录ID) - >这很奇怪,因为我没有尝试通过这些导航属性插入数据,我只是想用外键将我的主实体链接到那个辅助实体。
实体映射:
// WorkOrder Entity Mapping:
modelBuilder.Entity<WorkOrder>().ToTable("WorkOrder");
modelBuilder.Entity<WorkOrder>().Property(x => x.Id).HasColumnName("IDWorkOrder");
modelBuilder.Entity<WorkOrder>().Property(x => x.CreatedBy).HasColumnName("IDUserCreated");
modelBuilder.Entity<WorkOrder>().Property(x => x.UpdatedBy).HasColumnName("IDUserUpdated");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDWOCategory");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDProblem");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDWOCostCenter");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDWOLocation");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDWOPriority");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDWOStatus");
modelBuilder.Entity<WorkOrder>().Property<int?>("IDWOTrade");
modelBuilder.Entity<WorkOrder>().Property<Guid?>("IDUserCompleted");
modelBuilder.Entity<WorkOrder>().Property<Guid?>("IDParentWO");
// WO Navigation Properties:
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Category).WithOne().HasForeignKey<WorkOrder>("IDWOCategory").HasPrincipalKey<Category>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Problem).WithOne().HasForeignKey<WorkOrder>("IDProblem").HasPrincipalKey<Problem>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.CostCenter).WithOne().HasForeignKey<WorkOrder>("IDWOCostCenter").HasPrincipalKey<CostCenter>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Location).WithOne().HasForeignKey<WorkOrder>("IDWOLocation").HasPrincipalKey<Location>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Priority).WithOne().HasForeignKey<WorkOrder>("IDWOPriority").HasPrincipalKey<Priority>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Status).WithOne().HasForeignKey<WorkOrder>("IDWOStatus").HasPrincipalKey<Status>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Trade).WithOne().HasForeignKey<WorkOrder>("IDWOTrade").HasPrincipalKey<Trade>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.Requester).WithOne().HasForeignKey<WorkOrder>("IDRequester").HasPrincipalKey<Requester>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.UserCompleted).WithOne().HasForeignKey<WorkOrder>("IDUserCompleted").HasPrincipalKey<User>(c => c.Id);
modelBuilder.Entity<WorkOrder>().HasOne(x => x.ParentWorkOrder).WithOne().HasForeignKey<WorkOrder>("IDParentWO").HasPrincipalKey<WorkOrder>(c => c.Id);
获取控制器中的数据:(像魅力一样!)
[HttpGet("{Id}")]
public async Task<ActionResult<List<WorkOrder>>> GetWorkOrders(Guid Id)
{
var result = await WorkOrdersContext.WorkOrders
.Include(x => x.Problem)
.Include(x => x.Status)
.Include(x => x.Requester)
.Include(x => x.ParentWorkOrder)
.Include(x => x.Category)
.Include(x => x.Trade)
.Include(x => x.Location)
.Include(x => x.CostCenter)
.Include(x => x.Priority)
.Where(x => x.Id == Id)
.ToListAsync();
return Ok(result);
}
在控制器中保存新数据:(它在哪里发生故障!)
[HttpPost]
public async Task<ActionResult<WorkOrder>> CreateWorkOrderFromPending([FromBody]WorkOrder call)
{
// Insert the Work Order to the DB:
DbContext.WorkOrders.Add(call);
var saveResult = await DbContext.SaveChangesAsync();
// Check if any oddities occurred during the save:
if (saveResult == 0) return BadRequest("An Error occurred during saving and the Call was not saved, please try again.");
// Return the Inserted Work Order:
return Ok(call);
}
在这里,当它试图保存新的工作订单时,由于映射类型(来自实体映射代码片段的问题,类别,成本中心等),它会抛出异常。它试图将数据保存为新实体而不是构建FK现有实体的关系。我认为这是我在Fluent API中缺少一些逻辑的地方!
任何帮助将不胜感激,因为很难将这个问题放到谷歌搜索的几个字!
感谢@ DavidBrowne-Microsoft,我有了答案,试图让我们过去与.NET Core共存的DB First东西不是一件容易的事,来自Code First背景,其中.Add()是有效的路径,很难看出.Attach()是如何做到这一点的。
[HttpPost]
public async Task<ActionResult<WorkOrder>> CreateWorkOrderFromPending([FromBody]WorkOrder call)
{
// Insert the Work Order to the DB:
// DbContext.WorkOrders.Add(call);
var entity = DbContext.WorkOrders.Attach(call);
entity.State = EntityState.Added;
var saveResult = await DbContext.SaveChangesAsync();
// Check if any oddities occurred during the save:
if (saveResult == 0) return BadRequest("An Error occurred during saving and the Call was not saved, please try again.");
// Return the Inserted Work Order:
return Ok(call);
}
使用.Attach()而不是.Add()完成了这个技巧,将实体放入并将FK映射到我的Fluent映射中各自的Shadow Properties!