EF CodeFirst中的MTM关系 - 更新困境

时间:2015-07-28 03:34:08

标签: entity-framework ef-code-first many-to-many

我遇到了Entity Framework 6.1.3 CodeFirst多对多关系的问题。我的模型基本上是这样的:

class Schedule
{
    int Id { get; set; }
}

class Contest
{
    int Id { get; set; }

    ICollection<Schedule> GameSchedules { get; set; }
}

我的上下文供参考:

class MyContext
{
    MyContext() : base("name=DefaultConnection")
    {
        // no lazy loading for us
        this.Configuration.LazyLoadingEnabled = false;

        // do not auto detect changes for me
        this.Configuration.AutoDetectChangesEnabled = false;

        // we don't want our stuff to be wrapped in proxies 
        this.Configuration.ProxyCreationEnabled = false;
    }
}

实体Farmework CodeFirst configuraiton:

class ContestConfiguration : EntityTypeConfiguration<Contest>
{
    ContestConfiguration()
    {
        // setup many-to-many table between game schedules and contests
        this.HasMany(contest => contest.GameSchedules)
            .WithMany(schedule => schedule.Contests)
            .Map(
                contestSchedule =>
                {
                    contestSchedule.MapLeftKey("ContestId");
                    contestSchedule.MapRightKey("ScheduleId");
                    contestSchedule.ToTable("ContestSchedule", "something");
                });
    }
}

在创建与现有计划的比赛后,我执行以下操作,并且我看到两个sql语句进入,一个创建比赛,一个创建MTM表的记录。

Contest Add(Contest entity)
{
    // setup schedules
    entity.GameSchedules.ToList().ForEach(schedule => this.Context.Entry(schedule).State = EntityState.Unchanged);

    // call base add method
    return base.Add(entity);
}

然而,当我尝试更新时,它是一个非常不同的故事。我尝试了很多方法,并且无法让CodeFirst更新MTM表中的关系。它或者尝试删除计划以及MTM记录,或者它什么都不做。关于如何实现这一令人兴奋的壮举的任何想法?

1 个答案:

答案 0 :(得分:0)

好的,想通了。首先,删除ManyToManyCascadeDeleteConvention或者从MTM表中删除每个DELETE,它也会尝试删除计划或竞赛。这是因为默认情况下,EntityFramework将级联删除设置为true。

// remove many-to-many cascade auto delete
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

现在这里是更新的代码 1.确保已将新计划复制到新集合 2.使用新数据修改现有实体(这可以在更新MTM表之前或之后完成) 3.为简单起见,我刚刚从MTM表中删除了与此链接的所有当前行,并为了简洁起见添加了新行。 4.保存更改以确保删除计划 5.现在添加新的 6.再次保存更改以确保添加新计划

public void Update(Contest entity)
{
    // (1) generate new collection so that the reference doesn't get overwritten
    var schedulesToAdd = entity.GameSchedules.ToList();

    // (2) get entry
    var entry = this.context.Entry(entity);

    // set entry to modified
    entry.State = EntityState.Modified;

    // save the current state
    this.Context.SaveChanges();

    // get the existing context from the db
    var existingContest = this.Set.Where(contest => contest.Id == entity.Id).Include(contest => contest.GameSchedules).SingleOrDefault();

    // get the object context
    var context = ((IObjectContextAdapter)this.Context).ObjectContext;

    // iterate over existing relationships and eliminate
    foreach (var existingSchedule in existingContest.GameSchedules.ToList())
    {
        var schedule = this.Context.Schedules.Find(existingSchedule.Id);

        // (3) mark relationship as deleted
        context.ObjectStateManager.ChangeRelationshipState(existingContest, schedule, contest => contest.GameSchedules, EntityState.Deleted);
    }

    // (4) save the current state
    result = this.SaveChanges();

    // iterate over new entity relationships and add them
    foreach (var newSchedule in schedulesToAdd)
    {
        // find the schedule
        var schedule = this.Context.Schedules.Find(newSchedule.Id);

        // (5) mark relationship as added
        context.ObjectStateManager.ChangeRelationshipState(existingContest, schedule, contest => contest.GameSchedules, EntityState.Added);
    }

    // (6) save the current state
    this.SaveChanges();
}

请记住,您需要提出一些更复杂的行为来删除eixsting关系并添加新的关系。这只是一个例子。