2016-09-27 5 views
5

में IDbAsyncQueryProvider मैं एक डॉट नेट कोर एप्लिकेशन में परीक्षण करने के लिए XUNIT का उपयोग कर रहा हूं।EntityFrameworkCore

मुझे ऐसी सेवा की जांच करने की आवश्यकता है जो आंतरिक रूप से मेरे डेटाकॉन्टेक्स्ट में डीबीसेट पर एसिंक क्वेरी बना रहा हो।

I've seen here जो मजाक कर रहा है कि डीबीसेट असीमित रूप से संभव है।

मेरी समस्या यह है कि IDbAsyncQueryProvider EntityframeworkCore में उपलब्ध नहीं प्रतीत होता है, जिसका मैं उपयोग कर रहा हूं।

क्या मैं यहां गलत हूं? क्या किसी और को यह काम मिल गया है? https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Query/Internal/IAsyncQueryProvider.cs

यह वह जगह है:

(एक लंबा दिन गया, उम्मीद है कि मैं सिर्फ कुछ सरल याद कर रहा हूँ)

संपादित

GitHub पर पूछ के बाद, मैं इस वर्ग इंगित मिला जो मैंने इसे लागू करने की कोशिश में अब तक प्राप्त किया है:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Threading; 
using System.Threading.Tasks; 
using Microsoft.EntityFrameworkCore.Query.Internal; 

namespace EFCoreTestQueryProvider 
{ 
    internal class TestAsyncQueryProvider<TEntity>: IAsyncQueryProvider 
    { 
     private readonly IQueryProvider _inner; 

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

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

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

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

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

     IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression) 
     { 
      return Task.FromResult(Execute<TResult>(expression)).ToAsyncEnumerable(); 
     } 

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

    internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, System.Collections.Generic.IAsyncEnumerable<T>, IQueryable<T> 
    { 
     public TestDbAsyncEnumerable(IEnumerable<T> enumerable) 
      : base(enumerable) 
     { } 

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

     public IAsyncEnumerator<T> GetAsyncEnumerator() 
     { 
      return new TestDbAsyncEnumerable<T>(this.AsEnumerable()).ToAsyncEnumerable(); 
     } 

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

     IAsyncEnumerator<T> IAsyncEnumerable<T>.GetEnumerator() 
     { 
      throw new NotImplementedException(); 
     } 

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

मैं अब, इस लागू करने के लिए कोशिश की है और विशेष रूप से इन दोनों तरीकों के आसपास कुछ और समस्या आ जाती है:

public IAsyncEnumerator<T> GetAsyncEnumerator() 
{ 
    return new TestDbAsyncEnumerable<T>(this.AsEnumerable()).ToAsyncEnumerable(); 
} 

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

मैं आशा करती हूं कि किसी ने मुझसे करने के लिए के रूप में सही दिशा में बात कर सकता है कि मैं क्या कर रहा हूँ गलत।

+0

आप किस नए मुद्दे में शामिल हैं? प्रश्न (और शीर्षक) में नए मुद्दों को जोड़ना चाहिए। –

+0

क्या आपको इसका समाधान मिला? – Dan

+0

@ डैन मैं बिना किसी समाधान के आगे बढ़ रहा था। – Chris

उत्तर

5

मुझे अंत में यह काम करने के लिए मिला। वे थोड़ा IAsyncEnumerable को IDbAsyncEnumerable से EntityFrameworkCore में इंटरफेस बदल तो निम्नलिखित कोड मेरे लिए काम किया:

public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T> 
{ 
    public AsyncEnumerable(Expression expression) 
     : base(expression) { } 

    public IAsyncEnumerator<T> GetEnumerator() => 
     new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator()); 
} 

public class AsyncEnumerator<T> : IAsyncEnumerator<T> 
{ 
    private readonly IEnumerator<T> enumerator; 

    public AsyncEnumerator(IEnumerator<T> enumerator) => 
     this.enumerator = enumerator ?? throw new ArgumentNullException(); 

    public T Current => enumerator.Current; 

    public void Dispose() { } 

    public Task<bool> MoveNext(CancellationToken cancellationToken) => 
     Task.FromResult(enumerator.MoveNext()); 
} 

[Fact] 
public async Task TestEFCore() 
{ 
    var data = 
     new List<Entity>() 
     { 
      new Entity(), 
      new Entity(), 
      new Entity() 
     }.AsQueryable(); 

    var mockDbSet = new Mock<DbSet<Entity>>(); 

    mockDbSet.As<IAsyncEnumerable<Entity>>() 
     .Setup(d => d.GetEnumerator()) 
     .Returns(new AsyncEnumerator<Entity>(data.GetEnumerator())); 

    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.Provider).Returns(data.Provider); 
    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.Expression).Returns(data.Expression); 
    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.ElementType).Returns(data.ElementType); 
    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 

    var mockCtx = new Mock<SomeDbContext>(); 
    mockCtx.SetupGet(c => c.Entities).Returns(mockDbSet.Object); 

    var entities = await mockCtx.Object.Entities.ToListAsync(); 

    Assert.NotNull(entities); 
    Assert.Equal(3, entities.Count()); 
} 

आप और भी अधिक AsyncEnumerable और AsyncEnumerator के उन लोगों के परीक्षण कार्यान्वयन को साफ करने में सक्षम हो सकता है। मैंने कोशिश नहीं की, मुझे बस काम करने के लिए मिला।

याद रखें अपने DbSet अपने DbContext जरूरतों पर virtual के रूप में चिह्नित किया जाना है या फिर आप इस काम को सही रखने का DbContext पर कुछ इंटरफेस आवरण को लागू करने की आवश्यकता होगी।