我正在为我的组织建立一个会议注册网站,有多位贵宾和嘉宾发言人。要求是跟踪每个与会者的许多细节,包括他们的到达和离开计划以及他们当地的住宿信息。为了便于与利益相关者讨论我们需要构建的报告类型,我想用CSV中的一批记录填充我的开发数据库,其中包含随机生成的信息,如姓名,到达/离开日期/时间等。这将允许我们查看工作现场,而无需多次注册和重新注册。
但是,我只是不能让Seed方法正确保存相关记录,但处理注册的控制器工作正常。
我的数据库结构基本上是一个参与者实体,其中包含TravelSchedule
,LodgingArrangement
和各种查找的子实体。以下是我的实体的摘录:
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实体,并使用附加的TravelSchedule保存生成的参与者。
除非这不起作用。相反,上面的代码将TravelSchedule记录添加到数据库中,但AttendeeId始终在表中设置为0。此外,Attendees表中还填充了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();
}
这完美无缺。在用户确认注册完成之后,这些对象都不在数据库中。所以我不明白为什么我可以在这里将新实体持久化到数据库中,但我不能在我看来在上面的种子方法中做同样的事情。
非常感谢任何帮助或想法。这几天来我一直在悲伤。感谢。
答案 0 :(得分:1)
Attendee
和TravelSchedule
之间的关联是1:1。 EF通过在依赖实体(此处为:TravelSchedule
)中创建主键来实现1:1关联,该实体也是主体的外键实体(Attendee
)。
因此Attendee.TravelScheduleId
和TravelSchedule.AttendeeId
不会用于关联,其值仍为0.这意味着:Seed
无法使用这些字段/属性(我甚至可以期望它与一起工作,它通过Id
字段建立关联。