2015-07-28 7 views
0

У меня возникла проблема с инфраструктурой Entity Framework 6.1.3 CodeFirst Отношение «многие ко многим». Моя модель, по существу, например, так:MTM-отношения в EF 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; 
    } 
} 

Entity 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, либо ничего не делает. Любые идеи о том, как достичь этого умного дуновения?

ответ

0

Хорошо, понял. Прежде всего, удалите ManyToManyCascadeDeleteConvention, а также на каждом DELETE из таблицы MTM, он также попытается удалить расписание или конкурс. Это связано с тем, что по умолчанию 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 и добавления новых. Это было просто иллюстрацией.

Смежные вопросы