Не удалось запросить базу данных с использованием Entity Framework из-за ошибки IDbAsyncEnumerable - PullRequest
0 голосов
/ 26 августа 2018

Первоначально я получал эту ошибку:

Произошло исключение System.InvalidOperationException
HResult = -2146233079
Сообщение = Исходный IQueryable не реализует IDbAsyncEnumerable.Только источники, которые реализуют IDbAsyncEnumerable, могут использоваться для асинхронных операций Entity Framework.Для получения дополнительной информации см. http://go.microsoft.com/fwlink/?LinkId=287068.

Source = EntityFramework

StackTrace: at System.Data.Entity.QueryableExtensions.AsDbAsyncEnumerable [T] (источник IQueryable 1 source)<br> at System.Data.Entity.QueryableExtensions.ToListAsync[TSource](IQueryable 1)
в Cpr.Apps.Tam.Model.Utilities.DataSnapshot`1.d__18.MoveNext () в C: \ Projects \ MyApp \ MyAppModel \ Cpr.Apps.Tam.Model \ Utilities \ DataSnapshot.cs: строка 160

InnerException:

Поэтому я пытаюсь использовать этот код (см. @ ответ Тони О'Хагана в IDbAsyncEnumerable не реализован , со страницы онссылка https://msdn.microsoft.com/en-us/data/dn314429#async):

Вот исходный код:

public static class AsyncQueryableExtensions
{
    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }
}

internal class DbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
    private readonly IQueryProvider _inner;

    internal DbAsyncQueryProvider(IQueryProvider inner)
    {
        _inner = inner;
    }

    public IQueryable CreateQuery(Expression expression)
    {
        return new DbAsyncEnumerable<TEntity>(expression);
    }

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public object Execute(Expression expression)
    {
        return _inner.Execute(expression);
    }

    public TResult Execute<TResult>(Expression expression)
    {
        return _inner.Execute<TResult>(expression);
    }

    public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute(expression));
    }

    public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute<TResult>(expression));
    }
}

internal class DbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
    public DbAsyncEnumerable(IEnumerable<T> enumerable)
        : base(enumerable)
    { }

    public DbAsyncEnumerable(Expression expression)
        : base(expression)
    { }

    public IDbAsyncEnumerator<T> GetAsyncEnumerator()
    {
        return new DbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
    }

    IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
    {
        return GetAsyncEnumerator();
    }

    IQueryProvider IQueryable.Provider
    {
        get { return new DbAsyncQueryProvider<T>(this); }
    }
}

internal class DbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
    private readonly IEnumerator<T> _inner;

    public DbAsyncEnumerator(IEnumerator<T> inner)
    {
        _inner = inner;
    }

    public void Dispose()
    {
        _inner.Dispose();
    }

    public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(_inner.MoveNext());
    }

    public T Current
    {
        get { return _inner.Current; }
    }

    object IDbAsyncEnumerator.Current
    {
        get { return Current; }
    }
}

Обратите внимание, что я получаю следующую ошибку:

System.NullReferenceException не обработанопо коду пользователя HResult = -2147467261 Сообщение = ссылка на объект не установлена ​​для экземпляра объекта.
Источник = анонимно размещенная сборка DynamicMethods

StackTrace:
в lambda_method (Closure, DefectSummary)
в System.Linq.Enumerable.WhereListIterator 1.MoveNext()<br> at System.Linq.Enumerable.<DistinctIterator>d__64 1.MoveNext ()
в System.Linq.Buffer 1..ctor(IEnumerable 1 источник)
в System.Linq.OrderedEnumerable 1.<GetEnumerator>d__1.MoveNext()<br> at System.Linq.Enumerable.<DistinctIterator>d__64 1.MoveNext ()
в System.Linq.Enumerable.d__25 1.MoveNext()<br> at MyApp.Model.Utilities.DbAsyncEnumerator 1.MoveNextAsync (CancellationToken cancellationToken) в C: \ Projects \ MyApp \ Model \ Utilities \ AsyncQueryableExtensions.cs: строка 125
в System.Data.Entity.Infrastructure.IDbAsyncEnumerableExtensions.d__5`1.MoveNext: 10Next: 10):

Есть ли у кого-нибудь предложения, чтобы определить, как я могу найти нулевое значение, которое вызывает исключение?Это происходит в этой функции:

    public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(_inner.MoveNext());
    }

Когда я проверяю _inner, мне не ясно, какая часть переменной вызывает нулевую ошибку:

-       _inner  {System.Linq.Enumerable.<TakeIterator>d__25<MyApp.Model.Entities.DefectSummary>}    System.Collections.Generic.IEnumerator<MyApp.Model.Entities.DefectSummary> {System.Linq.Enumerable.<TakeIterator>d__25<MyApp.Model.Entities.DefectSummary>}
+       Non-Public members      
-       Results View    Expanding the Results View will enumerate the IEnumerable   
-       Data    {System.Collections.ListDictionaryInternal} System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
        Count   0   int
        IsFixedSize false   bool
        IsReadOnly  false   bool
        IsSynchronized  false   bool
-       Keys    {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}  System.Collections.ICollection {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}
+       Non-Public members      
-       Results View    Expanding the Results View will enumerate the IEnumerable   
        Empty   "Enumeration yielded no results"    string
        SyncRoot    {object}    object
+       Values  {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}  System.Collections.ICollection {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}
+       Non-Public members      
+       Results View    Expanding the Results View will enumerate the IEnumerable   
        HResult -2147467261 int
        HelpLink    null    string
+       InnerException  null    System.Exception
        Message "Object reference not set to an instance of an object." string
        Source  "Anonymously Hosted DynamicMethods Assembly"    string
        StackTrace  "   at lambda_method(Closure , DefectSummary )\r\n   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()\r\n   at System.Linq.Enumerable.<DistinctIterator>d__64`1.MoveNext()\r\n   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)\r\n   at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__1.MoveNext()\r\n   at System.Linq.Enumerable.<DistinctIterator>d__64`1.MoveNext()\r\n   at System.Linq.Enumerable.<TakeIterator>d__25`1.MoveNext()\r\n   at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()"   string
+       TargetSite  {Boolean lambda_method(System.Runtime.CompilerServices.Closure, MyApp.Model.Entities.DefectSummary)}    System.Reflection.MethodBase {System.Reflection.Emit.DynamicMethod.RTDynamicMethod}
+       Static members      
+       Non-Public members      

ОБНОВЛЕНИЕ:

К вашему сведению, это функция более высокого уровня, для которой настроен запрос:

    public IQueryable<Defect> GetLoadQuery()
    {
        IQueryable<Defect> query = null;
        // Call to stored procedure GetDefects
        var defectList = DbContext.GetDefects(null, null).ToList();
        var defects = new List<Defect>();

        using (IDefectDataService dataService = ServiceLocator.Current.GetInstance<IDefectDataService>())
        {
            foreach (var i in defectList)
            {
                dataService.DefectId = i.NotificationNo;
                NotificationLinearAsset notificationLam = dataService.GetNotificationLinearAsset();
                decimal? startPoint = notificationLam.StartPoint;
                decimal? endPoint = notificationLam.EndPoint;
                defects .Add(new Defect()
                {
                    NotificationNo = i.NotificationNo,
                    Priority = i.Priority,
                    ReportedBy = i.ReportedBy,
                    MeasuringDocument = i.MeasuringDocument,
                    AssetTypeDescription = i.AssetTypeDescription,
                    StartPoint = startPoint,
                    EndPoint = endPoint,
                    Description = i.Description,
                    AssetId = i.AssetId,
                });
            }
            query = defectSummaries.AsQueryable();
            // Other code here for filtering results...
        }

        return query.AsAsyncQueryable();
    }

ОБНОВЛЕНИЕ 2:

Этостановится еще более странным, потому что, если я закомментирую эти две строки, запрос сработает и выдаст результаты:

                //StartPoint = startPoint,
                //EndPoint = endPoint,

Но когда я ставлю условную точку останова в foreach, чтобы остановиться, если либо startPoint или endPoint равно нулю, отладчик никогда не останавливается.

ОБНОВЛЕНИЕ 3:

Спасибо за предложение, @ Иван Стоев .Обратите внимание, что сегодня я выполнил еще один тест, не меняя код, кроме комментария StartPoint/EndPoint, и он работает без ошибок, поэтому я не уверен, почему это так.Возможно, что-то было кешировано в Visual Studio?

1 Ответ

0 голосов
/ 26 сентября 2018

Устранена проблема, вместо использования результатов хранимой процедуры, которая создает тип GetDefect_Result, а затем преобразовывает его в тип Defect для использования приложением MVVM в вышеуказанном цикле foreach, вместо этого я создал представление и использует результаты этого представления, которые напрямую сопоставляются с результатами типа Defect. Это решение также включает удаление всех ссылок на IDbAsyncEnumerable.

    public IQueryable<Defect> GetLoadQuery()
    {
        IDbSet<Defect> dbSet = DbContext.Defects;

        IQueryable<Defect> query = dbSet.AsQueryable();

        // Other code here for filtering results...
        return query;
    }

К вашему сведению, я хотел использовать хранимую процедуру, потому что база данных, которую я использую, обычно не может оптимизировать представление, если оно имеет подпредставления, но в конечном итоге я смог использовать представление, добавив больше индексов в связанные таблицы для улучшить производительность базы данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...