为什么我的Seed()方法没有正确保存和连接实体

本文关键字:确保 保存 实体 连接 Seed 我的 方法 为什么 | 更新日期: 2023-09-27 18:23:34

我正在为我的组织建立一个会议注册网站,有多名贵宾和特邀发言人。要求跟踪每位与会者的许多详细信息,包括他们的到达和离开计划以及他们在当地的住宿信息。为了便于与利益相关者讨论我们需要构建的报告类型,我想用CSV中的一批记录填充我的开发数据库,其中包含随机生成的信息,如姓名、到达/离开日期/时间等。这将使我们能够查看工作现场,而无需多次注册和重新注册。

然而,我只是无法获得Seed方法来正确保存相关记录,但我处理注册的控制器工作得很好。

我的数据库结构基本上是一个Attendee实体,具有TravelScheduleLodgingArrangement和各种查找的子实体。以下是我的实体摘录:

public class Attendee
{
    public int Id { get; set; }
    ... other strings/etc ...
    public virtual TravelSchedule TravelSchedule { get; set; }
    public int TravelScheduleId { get; set; }
    public virtual LodgingArrangment LodgingArrangement { get; set; }
    public int LodgingArrangementId { get; set; }
}
public class TravelSchedule
{
    public int Id { get; set; }
    ... other properties ...
    public virtual Attendee Attendee { get; set; }
    public int AttendeeId { get; set; }
}
public class LodgingArrangement
{
    public int Id { get; set; }
    ... other properties ...
    public virtual Attendee Attendee { get; set; }
    public int AttendeeId { get; set; }
}

以下是我的上下文的OnModelCreating方法的内容:

modelBuilder.Entity<Attendee>()
    .HasOptional(a => a.TravelSchedule)
    .WithRequired(r => r.Attendee);
modelBuilder.Entity<TravelSchedule>()
            .HasRequired(m => m.ArrivalMode)
            .WithMany(m => m.Arrivals)
            .HasForeignKey(m => m.ArrivalModeId)
            .WillCascadeOnDelete(false);
modelBuilder.Entity<TravelSchedule>()
            .HasRequired(m => m.DepartureMode)
            .WithMany(m => m.Departures)
            .HasForeignKey(m => m.DepartureModeId)
            .WillCascadeOnDelete(false);
modelBuilder.Entity<Attendee>()
            .HasOptional(a => a.LodgingArrangement)
            .WithRequired(l => l.Attendee);

以下是我的种子方法的摘录。

var attendees = GetAttendeesFromCsv();
context.Attendees.AddOrUpdate(a => a.Email, attendees.ToArray());
context.SaveChanges();
var dbAttendees = context.Attendees.ToList();
foreach (var attendee in dbAttendees)
{
        attendee.TravelSchedule = CreateTravelSchedule();
        context.Entry<Attendee>(attendee).State = EntityState.Modified;
        context.SaveChanges();
}

由于使用了CsvHelper包,GetAttendeesFromCsv()将CSV中的记录提取到Attendee对象中。CreateTravelSchedule创建一个新的TravelSchedule实体,并使用extensionmethod.com中的SelectRandom()方法用查找表中的数据填充它。最重要的是,我将CSV行提取到Attendee对象中,添加一个随机生成的新TravelSchedule实体,并将生成的Attendee与附件TravelSchedule一起保存。

但这不起作用相反,上面的代码将TravelSchedule记录添加到数据库中,但表中的AttendeeId始终设置为0。此外,与会者表中填充了CSV中的所有记录,但每行的TravelScheduleId也始终为0。但是,当与调试器参与者一起执行update-database调用时。Id填充正确,因此根据我的理解,EF应该发现两者是相关的,并与与会者同时保留相关的TravelSchedule。那么EF为什么不把这两张唱片联系起来呢?

将循环更改为:

foreach (var attendee in dbAttendees)
{
    var travel = CreateTravelSchedule();
    travel.AttendeeId = attendee.Id;  // I also tried just travel.Attendee = attendee, without success
    context.TravelSchedules.Add(travel);
    context.SaveChanges();
}

导致此错误的结果:

System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.TravelSchedules_dbo.Attendees_Id". The conflict occurred in database "MySite.DAL.MyContext", table "dbo.Attendees", column 'Id'.

因此,我似乎无法将TravelSchedule实体添加到与会者,我也无法通过创建TravelSchedule然后附加与会者来"倒退"。

令人沮丧的是,我的控制器中的注册表逻辑运行良好,摘录如下。演练是,注册控制器使用静态WorkflowManager类在会话中存储每个屏幕的数据(视图模型),该类处理屏幕之间的持久性。用户确认后,控制器从WorkflowManager中提取每个屏幕的详细信息,通过AutoMapper运行这些信息,将其转换为相关的已填充DAL实体,将这些实体附加到与会者实体,并将其全部保存到数据库中。

同样,这非常好,可以毫无错误地保存与会者及其两个子实体。以下是控制器动作的相关摘录:

var attendeeRegistration = WorkflowManager.GetAttendeeRegistration();
var travelRegistration = WorkflowManager.GetTravelRegistration();
using (var db = new MyContext())
{
    var attendee = Mapper.Map<Attendee>(attendeeRegistration);
    attendee.AnotherChildEntity = db.ChildEntities.Find(attendeeRegistration.SelectedChildEntityId);
    var travel = Mapper.Map<TravelSchedule>(travelRegistration);
    travel.ArrivalMode = db.TravelModes.Find(travelRegistration.SelectedArrivalModeId);
    travel.DepartureMode = db.TravelModes.Find(travelRegistration.SelectedDepartureModeId);
    var lodging = Mapper.Map<LodgingArrangement>(lodgingRegistration);
    lodging.LodgingLocation = db.LodgingLocations.Find(lodgingRegistration.SelectedLodgingLocationId);
    attendee.Comments = comments;
    attendee.TravelSchedule = travel;
    attendee.LodgingArrangement = lodging;
    db.Attendees.Add(attendee);
    db.SaveChanges();
}

这非常有效。在用户确认注册完成之前,这些对象都不在数据库中。所以我不明白为什么我可以在这里将新实体持久化到数据库中,但我不能做上面Seed方法中看起来相同的事情。

非常感谢任何帮助或想法。这几天来一直给我带来无尽的悲痛。谢谢

为什么我的Seed()方法没有正确保存和连接实体

AttendeeTravelSchedule之间的关联为1:1。EF通过在依赖实体(此处:TravelSchedule)中创建主键来实现1:1关联,该主键也是其主体主体(Attendee)的外键。

因此CCD_ 11和CCD_ 12不用于关联,并且它们的值保持为0。这意味着:Seed在没有这些字段/属性的情况下工作(我甚至希望它能与一起工作),它通过Id字段建立关联。