sintaxis query inner framework consultas c# .net linq linq-to-sql entityset

c# - query - EntitySet: ¿hay alguna razón para que IList.Add no se establezca?



linq entity framework c# (3)

Hay 3 formas de agregar elementos a la mayoría de las listas ...

  • a través de un método de API público directo, típicamente Add(SomeType)
  • a través de la interfaz genérica IList<T>.Add(T)
  • a través del método de interfaz no genérico IList.Add(object)

y normalmente espera que se comporten más o menos igual. Sin embargo, EntitySet<T> LINQ es ... peculiar tanto en 3.5 como en 4.0; la API IList no IList el conjunto como "asignado" - los otros dos mecanismos sí lo hacen - esto suena trivial, pero es importante porque influye fuertemente en la serialización (es decir, hace que se omita) en el código repetitivo.

Ejemplo:

EntitySet<string> set1 = new EntitySet<string>(); set1.Add("abc"); Debug.Assert(set1.Count == 1); // pass Debug.Assert(set1.HasLoadedOrAssignedValues, "direct"); // pass EntitySet<string> set2 = new EntitySet<string>(); IList<string> typedList = set2; typedList.Add("abc"); Debug.Assert(set2.Count == 1); // pass Debug.Assert(set2.HasLoadedOrAssignedValues, "typed list"); // pass EntitySet<string> set3 = new EntitySet<string>(); IList untypedList = set3; untypedList.Add("abc"); Debug.Assert(set3.Count == 1); // pass Debug.Assert(set3.HasLoadedOrAssignedValues, "untyped list"); // FAIL

Ahora ... esto es profundamente sorprendente para mí; tanto que me tomó más de 2 horas de seguimiento hacia arriba a través del código para aislar lo que estaba sucediendo. Asi que...

¿Hay alguna razón sensata para esto? ¿O es solo un error?

(FWIW, también hubo un problema en el set.Assign(set) en 3.5, pero ahora está arreglado en 4.0).


Curiosamente, esto ha sido identificado para varias versiones ahora (usted indicó que un problema de 3.5 se corrigió en 4.0). Aquí hay una publicación de 2007. El resto de los métodos IList en 4.0 están correctamente relacionados con los métodos IList<T> . Creo que hay 2 explicaciones probables (de la variedad bug / feature):

  1. Este es un error real que Microsoft aún no ha corregido.
  2. Esta es una característica que otros códigos de Microsoft están aprovechando aprovechando para agregar elementos sin establecer los HasLoadedOrAssignedValues .

Probablemente ambas cosas: un error que cuenta con otro código dentro del marco. Parece que alguien se dijo a sí mismo:

Nadie realmente va a convertir esto en un IList y luego llama al método Add, ¿verdad?


Parece un error para mí. ILSpy muestra las diferencias entre las dos implementaciones:

int IList.Add(object value) { TEntity tEntity = value as TEntity; if (tEntity == null || this.IndexOf(tEntity) >= 0) { throw Error.ArgumentOutOfRange("value"); } this.CheckModify(); int count = this.entities.Count; this.entities.Add(tEntity); this.OnAdd(tEntity); return count; } // System.Data.Linq.EntitySet<TEntity> /// <summary>Adds an entity.</summary> /// <param name="entity">The entity to add.</param> public void Add(TEntity entity) { if (entity == null) { throw Error.ArgumentNull("entity"); } if (entity != this.onAddEntity) { this.CheckModify(); if (!this.entities.Contains(entity)) { this.OnAdd(entity); if (this.HasSource) { this.removedEntities.Remove(entity); } this.entities.Add(entity); this.OnListChanged(ListChangedType.ItemAdded, this.entities.IndexOf(entity)); } this.OnModified(); } }

Parece que la implementación IList simplemente deja de llamar a un par de invocadores de eventos ( OnListChanged y OnModified ) en los que LINQ to SQL probablemente confía para rastrear sus cambios. Si esto hubiera sido intencional, habría esperado que también dejaran de llamar a OnAdd .

Por qué simplemente no tienen IList.Add arrojan el valor a TEntity y llaman al método genérico Add , me supera.


Sorprendentemente, la diferencia parece radicada en el hecho de que los IList.Add e IList<T>.Add realidad tienen una semántica diferente :

  • El método IList.Add falla si la entidad que se está agregando ya está presente
  • El LIst<T>.Add quita y luego vuelve a agregar una entidad si ya está presente

La razón aparente de esta diferencia es que el método de interfaz IList.Add se define para devolver el índice de la entidad añadida, que para una implementación típica de IList.Add siempre será el Count de la recopilación anterior al Add .

En cualquier caso, debido a que las dos implementaciones son intencionalmente diferentes, parece que los autores simplemente omitieron accidentalmente la llamada this.OnModified() en la versión de IList.Add .