针对我们的上下文,从EF6 DB First模型移开-我正在构建一个将EF Core Code First模型用于数据库上下文的ASP Core API。为了在滚动更新中做到这一点,我的上下文必须与当前的数据库架构存在,因此我使用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逻辑的地方!
任何帮助将不胜感激,因为要用谷歌搜索将这个问题用几句话说是很难的!
答案 0 :(得分:0)
感谢@ DavidBrowne-Microsoft,我得到了答案,试图让过去的DB First与.NET Core共存并不是一件容易的事,并且来自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映射向上映射到它们各自的阴影属性!