2015-07-21 5 views
15

In Entity Framework 6 è stato introdotto il metodo AddRange. È ottimo per i grandi inserti perché il metodo DbSet.Add attiva sempre DetectChanges che rallenta notevolmente il processo. Volevo solo utilizzare un codice esistente basato sull'interfaccia IDbSet quando ho realizzato che non ha il metodo AddRange. Esiste solo nella classe DbSet.Perché non esiste alcun metodo AddRange/RemoveRange nell'interfaccia IDbSet nell'entità 6?

Ho cercato su Google un po 'e ho trovato questa discussione - http://forums.asp.net/t/1978828.aspx?Why+is+there+no+AddRange+method+for+System+Data+Entity+IDbSet+T+ - ma non c'è una chiara conclusione sul motivo per cui il metodo AddRange in realtà non esiste nell'interfaccia IDbSet.

È un bug o c'è qualche buona ragione per non esserci? Qualche idea?

UPDATE

Qui https://entityframework.codeplex.com/workitem/2781 Microsoft mi ha dato una risposta:

Questo legato alla progettazione. L'approccio all'interfaccia non è stato ottimale per DbSet perché l'aggiunta di membri interrompe qualsiasi applicazione esistente che implementa l'interfaccia.

Dato che vogliamo essere in grado di aggiungere membri a DbSet, passiamo a un approccio di classe base in cui DbSet è una classe base che puoi direttamente prendere in giro o ereditare.

Qui ci sono alcuni link che mostrano come utilizzare DbSet piuttosto che IDbSet:

https://msdn.microsoft.com/en-us/data/dn314429

https://msdn.microsoft.com/en-us/data/dn314431

+0

Mi chiedo se fosse per la compatibilità con le versioni precedenti, in modo che le vecchie app con classi che implementano 'IDbSet' non si interrompessero improvvisamente perché non implementano il metodo' AddRange() '. –

+0

Ma, se ho ragione, accadrebbe solo se EF è stato aggiornato alla versione superiore. Durante questo aggiornamento credo che problemi del genere possano essere risolti. Tuttavia, forse hai ragione. – Landeeyo

+0

È possibile trasmettere l'oggetto al tipo DbSet senza problemi, giusto? –

risposta

15

Dal Entity Framework Design Meeting Notes, on May 16, 2013:

Il team ha riconosciuto il potenziale per le modifiche di rottura:

Le classi DbSet (generici e non generici) ereditare da un'interfaccia IDbSet (generici o non generico). IDbSet è inteso solo per creare duplicati di test, essere questi falsi o falsi.

Tuttavia, in EF6 DbSet è cambiato in quattro modi che se riflettono nei cambiamenti equivalenti per IDbSet sarebbe rompendo modifiche:

  • FindAsync aggiunti
  • AddRange/removeRange aggiunti
  • tipo di ritorno Local cambiato DbLocalView (questo cambiamento può essere ripristinato comunque)

Hanno discusso una serie di possibili modifiche in dettaglio, ma alla fine ha deciso di evitare il cambiamento di rottura, e di "rendere più DbSet mockable":

La decisione era quello di rendere più DbSet mockable. Tuttavia, IDbSet non sarà obsoleto perché ciò creerebbe lavoro per quelli che attualmente utilizzano IDbSet che non hanno bisogno di usare i nuovi membri. Aggiungiamo una guida a IDbSet che indica che l'utilizzo di DbSet è la via da seguire per ottenere un nuovo codice e, in base al feedback, potremmo scegliere IDbSet obsoleto in una versione futura.

E se si guarda il codice per IDbSet, hanno aggiunto commenti alla parte superiore dell'interfaccia:

IDbSet era originariamente destinato a consentire la creazione di test raddoppia (prende in giro o fakes) per DbSet. Tuttavia, questo approccio presenta problemi in quanto l'aggiunta di nuovi membri a un'interfaccia interrompe il codice esistente che implementa già l'interfaccia senza i nuovi membri.

Pertanto, a partire da EF6, nessun nuovo membro verrà aggiunto a questa interfaccia e si consiglia di utilizzare DbSet come classe base per i duplicati di prova.

+0

Grazie per la risposta completa :). – Landeeyo

+0

Prego @Landeeyo. –

1

questo non è sicuramente un bug ed è fatto in questo modo alla progettazione. È difficile rispondere a questo tipo di domande senza essere uno sviluppatore della libreria .NET, ma la mia ipotesi è che volessero mantenere semplici le interfacce. Forse qualcuno nel team di .NET vedrà questo e interverrà. I problemi di retrocompatibilità saranno legati all'interfaccia/implementazione concreta, che è anche sicuramente una possibilità in questo scenario. Tuttavia, questo ragionamento probabilmente non si baserà sul perché IList/ICollection non li definisce.

Un argomento è che aggiungendo AddRange (oltre a RemoveRange/InsertRange) all'interfaccia, si sta costringendo l'implementatore a definire tali metodi. Le interfacce dovrebbero essere semplici e facili da definire. I metodi AddRange, etc dovrebbero esistere solo su raccolte concrete dove è possibile vedere miglioramenti delle prestazioni. Ad esempio, un elenco può ottimizzare il suo AddRange aumentando opportunamente la sua capacità interna, ecc. Dove un semplice ciclo su voci e chiamate Add può essere più costoso (ad esempio tramite un metodo di estensione).

Probabilmente lo fanno per lo stesso motivo per cui IList, ICollection, ecc. Non hanno un AddRange direttamente sull'interfaccia ma eseguono le implementazioni concrete.

C'è una soluzione per questo, e cioè per astrarre sia l'interfaccia che la classe concreta usando la propria interfaccia/classe. Puoi dare alla tua interfaccia un AddRange ed estendere DBSet/implementare la tua interfaccia in un'altra classe. Questo può o non può funzionare a seconda di come si utilizza IDBSet/DBSet nel codice. Anche se, un piccolo refactoring può fare questo lavoro. Qualcosa del genere -

public class MyDbSet<TEntity> : DbSet<TEntity>, IMyDbSet<TEntity> where TEntity : class 
{ 
} 

public interface IMyDbSet<TEntity> : IDbSet<TEntity> where TEntity : class 
{ 
    IEnumerable<TEntity> AddRange(IEnumerable<TEntity> items); 
} 

Ora, puoi semplicemente usare IMyDbSet nel tuo codice. Non è necessario implementare AddRange poiché è già implementato estendendo DbSet. I metodi esterni che accettano solo IDbSet/DbSet dovrebbero comunque accettare MyDbSet/IMyDbSet.

Problemi correlati