2012-09-26 5 views
1

J'utilise entity Framework 4.1 qui interroge une base de données SQL Server 2008. Malheureusement, tous souvent nous obtenons l'exception ci-dessous:Entity Framework - System.IndexOutOfRangeException

<ExceptionType>System.IndexOutOfRangeException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType> 
    <Message>Index was outside the bounds of the array.</Message> 



at System.Data.SqlClient.SqlDataReader.ReadColumnHeader(Int32 i) 
    at System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i) 
    at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal) 
    at System.Data.Common.Internal.Materialization.Shaper.GetPropertyValueWithErrorHandling[TProperty](Int32 ordinal, String propertyName, String typeName) 
    at lambda_method(Closure , Shaper) 
    at System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet) 
    at lambda_method(Closure , Shaper) 
    at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper) 
    at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext() 
    at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) 
    at System.Linq.Queryable.First[TSource](IQueryable`1 source) 
    at OnlineSelfService.Business.ContentServiceBusiness.GetPageContent(Int32 pageId)</StackTrace> 

Le code réel exemple:

//Caller 
    public EmployeeEntity GetEmployeeDetail(int employeeID) 
    { 
     IQueryable<Employee> result=null; 
     if (myCaching.Contains("Employee")) 
      { 
       result = (IQueryable<Employee>)myCaching["Employee"]; 
      } 
      else 
      { 
       result = dataAccess.GetEmployeeDetail(); 
       myCaching.AddToCache("Employee", result); //Expire in 2min 
      } 

      IQueryable<Employee> entityResult = from entity in result 
                 where entity.employeeId == employeeID 
                 select entity; 
     if (entityResult.Count<Employee>() > 0) 
       return entityResult.First<Employee>(); 
      return new EmployeeEntity(); 
    } 

}

//DAL 
public IQueryable<Employee> GetEmployeeDetail() 
{ 
    DatabaseEntities ent = new DatabaseEntities(this._connectionString); 
    IQueryable<Employee> result = from employee in ent.EmployeeEntity 
              select employee; 

    return result; 
} 

MISE À JOUR ** Mise à jour mon code avec la mise en cache.

J'ai recherché sur Google et je n'ai pas trouvé de réponse définitive à la cause. Certains qui ont fait face à ce problème pourraient-ils partager une résolution?

Merci.

+0

Votre contexte n'est pas synchronisé avec la base de données? (Les colonnes de base de données ne correspondent pas aux propriétés de la classe?) –

+0

Problème se produit uniquement de façon aléatoire et je ne pense pas qu'il s'agit d'un problème de synchronisation. –

+0

Connexe: http://stackoverflow.com/questions/12617639/weird-random-exceptions –

Répondre

4

L'appel .Count() exécute la requête. Je ne pense pas que le .First() l'exécuterait à nouveau mais peut-être qu'il l'est, et quelque chose a changé entre ces appels. Vous pouvez essayer de réécrire la requête comme:

(from entity in result 
where entity.employeeId == employeeID 
select entity).FirstOrDefault() ?? new EmployeeEntity(); 
+0

J'ai mis à jour le code ci-dessus avec la mise en cache. Cela pourrait-il le provoquer? –

+0

@dskh Nice catch, il réexécute la requête, le compte ne récupère pas les données, il effectue juste un compte SQL, FirstOrDefault ressemble à la bonne solution ici – Guillaume86

+0

@ Guillaume86, merci pour votre réponse ce qui est pour IS pourquoi count ne serait pas récupérer des données? –

0

Essayez de revenir comme ceci:

return entityResult.First(e => e.employeeId == employeeID); 
0

Toute fonction appelée sur IEnumerable ou IQueryable ré-exécuter la requête ... qui est pourquoi il est pas bon mettre des choses comme ça dans les boucles. Vous finissez par des tonnes de requêtes à la base de données. Quant à savoir pourquoi il devient l'exception, j'utiliser .Tout() au lieu de comptage pour déterminer la longueur du résultat

return (entityResult.Any<Employee>() > 0) ? entityResult.First<Employee>() : new EmployeeEntity(); 

Bien que la logique est un peu déroutant, parce que vous voulez retourner un seul EmployeeEntity et la requête suggère que vous attendez seulement un retour. Donc, vous pouvez simplement utiliser

entityResult.Single<Employee>() 

qui lancera une exception si plus d'un est retourné à moins que vous ne pouvez pas gérer les exceptions dans l'appelant. Alors SingleOrDefault pourrait être mieux alors vérifier juste pour null et ne pas avoir un compte ou aucune vérification du tout. Quelques suggestions il ya toujours plusieurs façons de faire quelque chose