Отход от первых моделей EF6 DB для наших контекстов - я создаю ASP Core API, который использует модель EF Core Code First для контекстов базы данных. Чтобы сделать это в непрерывном обновлении, мои контексты должны существовать с текущей схемой БД, поэтому я использую EF Fluent API для построения сопоставлений сущностей для моделей Code First, которые не отражают текущую схему базы данных.
Я столкнулся с проблемой со свойствами навигации на объектах во время операций вставки. Получение данных из БД для первичного объекта прекрасно работает с использованием стандартного формата .Include (x => x.OtherEntity), и проблема заключается в сохранении первичного объекта в БД.
Использование Fluent API для отображения сущностей является для меня новым, поэтому, скорее всего, в этом и заключается проблема обучения. Я пытался работать с OwnsOne против HasOne, но документация MS предполагает, что HasOne () является правильным методом для выполнения этого сопоставления.
Моя основная сущность, о которой идет речь, имеет свойства тени для полей внешнего ключа, которые связывают ключ, когда я использую .HasOne () в отображении данных (в коде ниже)
Сообщения об исключениях в этом случае бесполезны, поскольку они не отражают проблему с отображением, они предполагают, что данные не могут быть вставлены, когда таблицы свойств навигации имеют столбцы идентификаторов (IE не может вставить запись с явным идентификатором) -> Это странно, потому что я не пытаюсь вставить данные через эти свойства навигации, я просто пытаюсь связать свою основную сущность с этой вторичной сущностью с помощью внешнего ключа.
Отображение сущностей:
// 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);
}
Здесь, когда он пытается сохранить новый рабочий заказ, он генерирует исключение из-за сопоставленных типов (проблема, категория, CostCenter и т. Д. Из фрагмента кода сопоставлений сущностей). Он пытается сохранить данные как новые сущности, а не построение отношений ФК на существующих предприятиях. Я думаю, что здесь мне не хватает логики с Fluent API!
Любая помощь будет принята с благодарностью, поскольку эту проблему довольно сложно описать несколькими словами для поиска в Google!