En Entity Framework 6 se ha introducido el método AddRange. Es excelente para inserciones grandes porque el método DbSet.Add siempre activa DetectChanges, lo que ralentiza extremadamente el proceso. Solo quería usar un código existente basado en la interfaz IDbSet cuando me di cuenta de que no tiene el método AddRange. Solo existe en la clase DbSet.
Busqué en Google un poco y encontré esta discusión: http://forums.asp.net/t/1978828.aspx?Why+is+there+no+AddRange+method+for+System+Data+Entity+IDbSet+T+ - pero no hay una conclusión clara sobre la razón por la cual el método AddRange no existe en la interfaz IDbSet.
¿Es un error o hay alguna buena razón para que no esté allí? ¿Algunas ideas?
ACTUALIZAR
Aquí https://entityframework.codeplex.com/workitem/2781 Microsoft me dio una respuesta:
Esto es por diseño. El enfoque de la interfaz no era bueno para DbSet porque agregar miembros rompe las aplicaciones existentes que implementan la interfaz.
Dado que queremos poder agregar miembros a DbSet, cambiamos a un enfoque de clase base donde DbSet es una clase base que puede simular o heredar directamente.
Aquí hay algunos enlaces que muestran cómo usar DbSet en lugar de IDbSet:
De las notas de la reunión de diseño de Entity Framework, el 16 de mayo de 2013 :
El equipo reconoció el potencial para romper cambios:
Las clases DbSet (genéricas y no genéricas) heredan de una interfaz IDbSet (genérica o no genérica). IDbSet está diseñado solo para crear dobles de prueba, ya sean simulacros o falsificaciones.
Sin embargo, en EF6, DbSet ha cambiado de cuatro maneras que, si se reflejan en cambios equivalentes para IDbSet, serían cambios importantes:
- FindAsync añadido
- AddRange/RemoveRange añadido
- El tipo de devolución local cambió a DbLocalView (este cambio se puede revertir de todos modos)
Discutieron un montón de posibles cambios en detalle, pero finalmente decidieron evitar el cambio importante y "hacer que DbSet sea más simulable":
La decisión fue hacer DbSet más simulable. Sin embargo, no obsoletaremos IDbSet porque esto crearía trabajo para aquellos que actualmente usan IDbSet que no necesitan usar los nuevos miembros. Agregaremos una guía a IDbSet que indique que el uso de DbSet es el camino a seguir para el nuevo código y, según los comentarios, podemos optar por dejar obsoleto a IDbSet en una versión futura.
Y si observa el código de IDbSet , agregaron comentarios en la parte superior de la interfaz:
IDbSet originalmente estaba destinado a permitir la creación de dobles de prueba (simulacros o falsificaciones) para DbSet. Sin embargo, este enfoque tiene problemas en el sentido de que agregar nuevos miembros a una interfaz rompe el código existente que ya implementa la interfaz sin los nuevos miembros.
Por lo tanto, a partir de EF6, no se agregarán nuevos miembros a esta interfaz y se recomienda usar DbSet como clase base para los dobles de prueba.
Esto definitivamente no es un error y se hace así por diseño. Es difícil responder a este tipo de preguntas sin ser un desarrollador de la biblioteca .NET, pero supongo que querían mantener las interfaces simples. Tal vez alguien en el equipo de .NET vea esto y comente. Los problemas de compatibilidad con versiones anteriores estarán vinculados a la interfaz/implementación concreta, que definitivamente también es una posibilidad en este escenario. Sin embargo, este razonamiento probablemente no se trasladará a por qué IList/ICollection no los define.
Un argumento es que al agregar AddRange (así como RemoveRange/InsertRange) a la interfaz, obliga al implementador a definir esos métodos. Las interfaces deben ser simples y fáciles de definir. Los métodos AddRange, etc. realmente solo deberían existir en colecciones concretas donde puede ver mejoras de rendimiento. Por ejemplo, una lista puede optimizar su AddRange aumentando adecuadamente su capacidad interna, etc. Donde un simple bucle sobre los elementos y llamar a Add puede ser más costoso (por ejemplo, a través de un método de extensión).
Probablemente hagan esto por la misma razón por la que IList, ICollection, etc. no tienen AddRange en la interfaz directamente, pero sí en las implementaciones concretas.
Hay una solución para esto, y es abstraer tanto la interfaz como la clase concreta usando su propia interfaz/clase. Puede darle a su interfaz un AddRange y extender DBSet/implementar su interfaz en otra clase. Esto puede o no funcionar dependiendo de cómo esté usando IDBSet/DBSet en su código. Aunque, un poco de refactorización puede hacer que esto funcione. Algo como esto --
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); }Ahora, solo puede usar IMyDbSet en su código. No es necesario implementar AddRange, ya que ya está implementado al extender DbSet. Los métodos externos que solo aceptan IDbSet/DbSet aún deben aceptar MyDbSet/IMyDbSet.