2015-12-01 18 views
6

Sto cercando di capire le migliori pratiche durante l'aggiornamento di un'entità e di tutti i suoi figli. Per esempio; Ho un servizio di aggiornamento "Datore di lavoro" che aggiornerebbe l'entità del datore di lavoro e le entità "Indirizzo" del datore di lavoro e le entità "Telefono" di ciascun "Indirizzo". L'utente può aggiungere nuovi indirizzi al datore di lavoro esistente oppure aggiornare gli indirizzi correnti o eliminarli, lo stesso vale per i telefoni di ciascun indirizzo. Potresti aiutarmi a scrivere il codice ideale che gestirà questo scenario.EF7 Come gestire l'operazione di aggiornamento per entità nidificate

Sto usando EF7 rc1 e utilizzo Automapper per mappare Dto to Entity nel mio servizio.

public partial class Employer 
{ 
    public int EmployerId { get; set; } 
    public int Name { get; set; } 

    [InverseProperty("Employer")] 
    public virtual ICollection<Address> Address { get; set; } 
} 

public partial class Address 
{ 
    public int AddressId { get; set; } 
    public int Address1{ get; set; } 
    public int City { get; set; } 

    [ForeignKey("EmployerId")] 
    [InverseProperty("Address")] 
    public virtual Employer Employer { get; set; } 

    [InverseProperty("Address")] 
    public virtual ICollection<Phone> Phone { get; set; } 
} 

public partial class Phone 
{ 
    public int PhoneId { get; set; } 
    public string Number { get; set; } 

    [ForeignKey("AddressId")] 
    [InverseProperty("Phone")] 
    public virtual Address Address { get; set; } 
} 

Il mio metodo di servizio;

public async Task<IServiceResult> Update(EmployerDto employer) 
{ 
var employerDbEntity = await _db.Employer 
      .Include(a=>a.Address).ThenInclude(p=>p.Phone) 
      .SingleOrDefaultAsync (a=>a.EmployerId == employer.EmployerId); 


//How to handle the update operation for children? 

var entity = Mapper.Map<Employer>(employer); 
HandleChildren(employerDbEntity,entity); 

await _db.SaveChangesAsync(); 
... 
... 
} 
private void HandleChildren(Employer employerDbEntity,Employer entity) 
{ 
     //Delete 
     foreach (var existing in employerDbEntity.Address.ToList()) 
     { 
      if (!entity.Address.Any(a => a.AddressId == existing.AddressId)) 
       employerDbEntity.Address.Remove(existing); 
     } 
     //Update or Insert 
     foreach (var address in entity.Address) 
     { 
      var existing = employerDbEntity.Address.SingleOrDefault(a =>a.AddressId == address.AddressId); 
      //Insert 
      if (existing == null) 
      { 
       employerDbEntity.Address.Add(address); 
      } 
      //Update 
      else 
      { 
       Mapper.Map(address, existing); 
      } 
     } 
} 

risposta

0

Questo esempio sembra un buon modo per gestire le raccolte secondarie. Ogni collezione deve essere controllata manualmente per l'azione eseguita. (Utilizzo di farmaci generici suona bene, ma morde sempre di nuovo in qualche modo In genere, le prestazioni..)

Con questo in mente, ecco alcune raccomandazioni:

  • Spostare la movimentazione in metodi/servizi separati collezione bambino.
  • Se si esegue una query per le entità esistenti, recuperare l'intera raccolta in una query quindi iterare i risultati nella memoria.
  • Poiché si sta scrivendo codice asincrono, è possibile sfruttare l'elaborazione delle raccolte secondarie in parallelo! Per fare ciò, ogni operazione dovrebbe creare il proprio contesto. This explains why it's faster.

Ecco un esempio utilizzando le raccomandazioni:

private async Task UpdateAddresses(List<Address> addressesToUpdate) 
{ 
    using(var context = new Context()) 
    { 

     var existingAddressIds = await context.Addresses 
       .Where(a => addressesToUpdate.Contains(a.AddressId)) 
       .ToListAsync() 
       .ConfigureAwait(false); 

     existingAddressIds.ForEach(a => context.Addresses.Remove(a));  

     await context.SaveChangesAsync().ConfigureAwait(false);  
    } 
} 
Problemi correlati