Обновление и удаление связанных записей в отношениях «один ко многим» с использованием Entity Framework - PullRequest
0 голосов
/ 23 февраля 2012

Использование кода EF 4.1 Во-первых, у меня есть объект Member , и он, в свою очередь, имеет два отношения " один-ко-многим " для HomeAddress и WorkAddress .Он также имеет логическое свойство для указания, использовать ли один из этих адресов или нет.

У меня есть две проблемы, которые я не могу выяснить:

  1. Каждый раз, когда я обновляю адрес участника, новая запись добавляется в таблицу MemberAddresses (с новымЗначение идентификатора) и существующая запись не удаляется.Хотя это выглядит хорошо с точки зрения внешнего интерфейса, так как HomeAddressId и WorkAddressId в родительской таблице Members обновляются с новой записью, старые записи хранятся в таблице (без изменений).Я не хочу добавлять новую адресную запись при обновлении адреса.Я только хочу обновить существующую запись.Если нужно добавить новый, я хотя бы хочу, чтобы он очистил старый.

  2. Бывают моменты, когда я хочу удалить запись адреса из таблицы.Например, если член ранее имел связанный HomeAddress, а позже DontUseHomeAddress установлен в true, я хочу, чтобы адрес был удален из таблицы.До сих пор я пытался установить его на ноль, но это просто предотвращает любые обновления.Это не удаляет его.

Я уверен, что я пропускаю только часть кода, поэтому я включаю весь соответствующий код ниже, который, я думаю, может повлиять на это.

public abstract class Entity 
{
  public int Id { get; set; }
}

public class Member : Entity
{
  public string Name { get; set; }
  public bool DontUseHomeAddress { get; set; }
  public virtual MemberAddress HomeAddress { get; set; }
  public bool DontUseWorkAddress { get; set; }
  public virtual MemberAddress WorkAddress { get; set; }
  //... other properties here ...
}

public class MemberMap : EntityTypeConfiguration<Member>
{
  public MemberMap()
  {
    ToTable("Members");
    Property(m => m.Name).IsRequired().HasMaxLength(50);
    //TODO: Somehow this is creating new records in the MemberAddress table instead of updating existing ones 
    HasOptional(m => m.HomeAddress).WithMany().Map(a => a.MapKey("HomeAddressId"));
    HasOptional(m => m.WorkAddress).WithMany().Map(a => a.MapKey("WorkAddressId"));
  }
}

public class MemberAddressMap : EntityTypeConfiguration<MemberAddress>
{
  public MemberAddressMap()
  {
    ToTable("MemberAddresses");
    Property(x => x.StreetAddress).IsRequired().HasMaxLength(255);
    Property(x => x.City).IsRequired().HasMaxLength(50);
    Property(x => x.State).IsRequired().HasMaxLength(2);
    Property(x => x.ZipCode).IsRequired().HasMaxLength(5);
  }
}

Вот метод InsertOrUpdate из моего класса репозитория, который вызывает мой контроллер:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : Entity
{
  private readonly EfDbContext _context;
  private readonly DbSet<TEntity> _dbSet;

  public Repository(EfDbContext context)
  {
    _context = context;
    _dbSet = _context.Set<TEntity>();
  }

  public bool InsertOrUpdate(TEntity entity)
  {
    if(entity.Id == 0)
    {
      _dbSet.Add(entity);
    }
    else
    {
      _context.Entry(entity).State = EntityState.Modified;
    }
    _context.SaveChanges();
    return true;
  }

  //... Other repository methods here ...
}

EDIT: добавление кода для UnitOfWork и MemberServices

открытый класс MemberServices: IMemberServices {private readonly IUnitOfWork _unitOfWork;приватный только для чтения IRepository _memberRepository;

  public MemberServices(IUnitOfWork unitOfWork)
  {
    _unitOfWork = unitOfWork;
    _memberRepository = unitOfWork.RepositoryFor<Member>();
  }

  public Member Find(int id)
  {
    return _memberRepository.FindById(id);
  }

  public bool InsertOrUpdate(Member member)
  {
//    if(member.HomeAddress != null)
//      _unitOfWork.SetContextState(member.HomeAddress, EntityState.Modified);
//
//    if(member.WorkAddress != null)
//      _unitOfWork.SetContextState(member.WorkAddress, EntityState.Modified);
//
//    if(member.DontUseHomeAddress)
//    {
//      //TODO: This is an attempted hack... fix it by moving somewhere (possibly to repository)
//      var context = new EfDbContext();
//      context.Set<MemberAddress>().Remove(member.HomeAddress);
//      context.SaveChanges();
//    }  

    _memberRepository.InsertOrUpdate(member);
    return true;
  }
}

public class UnitOfWork : IUnitOfWork
{
  private readonly EfDbContext _context;

  public UnitOfWork()
  {
    _context = new EfDbContext();
  }

  public IRepository<T> RepositoryFor<T>() where T : Entity
  {
    return new Repository<T>(_context);
  }

  public void Attach(Entity entity)
  {
    _context.Entry(entity).State = EntityState.Unchanged;
  }

  public void SetContextState(Entity entity, EntityState state)
  {
    _context.Entry(entity).State = state;
  }

  public void Save()
  {
    _context.SaveChanges();

  }
}

1 Ответ

2 голосов
/ 23 февраля 2012

Установка состояния _context.Entry(entity).State = EntityState.Modified; не влияет на состояние связанных объектов.Если вы хотите позаботиться об изменениях связанных объектов, вы должны также установить их состояние на Modified:

if (member.HomeAddress != null)
    _context.Entry(member.HomeAddress).State = EntityState.Modified;
if (member.WorkAddress != null)
    _context.Entry(member.WorkAddress).State = EntityState.Modified;
_context.Entry(member).State = EntityState.Modified;

Это больше не является общим.должен вызвать соответствующий метод для удаления объекта;установка свойства навигации на null недостаточно:

_context.MemberAddresses.Remove(member.HomeAddress);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...