Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GetAsync() and Include #54

Closed
ravenpride opened this issue Nov 20, 2016 · 10 comments
Closed

GetAsync() and Include #54

ravenpride opened this issue Nov 20, 2016 · 10 comments

Comments

@ravenpride
Copy link

There seems to be an issue with the GetAsync() method. I'm writing a small library to maintain the database of my private mail server and tried to query a SQLite database. The "MailAccount" class contains a property to the "Domain" the mail account belongs to. Furthermore a property of type long annotated with the ForeignKey attribute points to the "Domain" property.

The following line works as expected:
MailAccount account = connection.Get(new MailAccount { Id = id }, statements =>statements.Include<Domain>(x => x.LeftOuterJoin()));

The asynchronous equivalent does not:
MailAccount account = await connection.GetAsync<MailAccount>(new MailAccount { Id = id }, statements => statements.Include<Domain>(x => x.LeftOuterJoin()));

Is there something I should additionally consider when using the asynchronous API functions?

@MoonStorm
Copy link
Owner

What issue are you experiencing?

@ravenpride
Copy link
Author

An InvalidOperationException is thrown when calling GetAsync().

Exception Text:
Invalid attempt to call FieldCount when reader is closed.

Stack Trace:

   at Microsoft.Data.Sqlite.SqliteDataReader.get_FieldCount()
   at Dapper.SqlMapper.GetColumnHash(IDataReader reader, Int32 startBound, Int32 length)
   at Dapper.SqlMapper.<MultiMapImpl>d__139`8.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at Dapper.FastCrud.SqlStatements.RelationshipSqlStatements`1.<SelectByIdAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at CloudyCube.Api.Persistence.Repositories.MailAccountRepository.<GetByIdAsync>d__3.MoveNext() in D:\Visual Studio Projects\CloudyCube\CloudyCube\src\ManagerAPI\Persistence\Repositories\MailAccountRepository.cs:line 59

Oh. if it matters, I'm using .NET Core 1.0.1.

@MoonStorm
Copy link
Owner

Dapper is suffering from a bug that causes the async methods to fail.

@ravenpride
Copy link
Author

Ok, I'll try to work around it. Thank you very much for the explanation!

@generik0
Copy link

generik0 commented Dec 12, 2016

Hi.
I am having the same issue. But i get:
"<System.InvalidOperationException: No columns were selected".

The normal Get works, but not the async. Look the code is identical...:

image

Her is the exception from the unit test:

Expected: No Exception to be thrown
But was: <System.InvalidOperationException: No columns were selected
at Dapper.SqlMapper.GetNextSplit(Int32 startIdx, String splitOn, IDataReader reader)
at Dapper.SqlMapper.GenerateDeserializers(Type[] types, String splitOn, IDataReader reader)
at Dapper.SqlMapper.d__1408.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source) at Dapper.FastCrud.SqlStatements.RelationshipSqlStatements1.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at SE.QuotationRepository.Tests.QuotationItemRepositoryTests.<>c__DisplayClass2_0.<<Order2_GetIdAsync_Return_Works>b__0>d.MoveNext() in S:\Dropbox\My Documents\01 Projects\SEDK\TelemecaniqueSensorsQuotation\Tests\Business\SE.QuotationRepository.Tests\QuotationItemRepositoryTests.cs:line 92
--- End of stack trace from previous location where exception was thrown ---
at NUnit.Framework.Internal.ExceptionHelper.Rethrow(Exception exception)
at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult)
at NUnit.Framework.Constraints.ThrowsConstraint.ExceptionInterceptor.Intercept(Object invocation)>

at SE.QuotationRepository.Tests.QuotationItemRepositoryTests.Order2_GetIdAsync_Return_Works() in S:\Dropbox\My Documents\01 Projects\SEDK\TelemecaniqueSensorsQuotation\Tests\Business\SE.QuotationRepository.Tests\QuotationItemRepositoryTests.cs:line 90

Wierd that the native dapper works...


public async Task<QuotationItem> GetIdAsync( int id, IDbConnection connection=null)
        {
                var query = "Select item.*, product.*, item.id as Id, item.productId as productId from QuotationItem as item " +
                    "INNER JOIN Product as product on item.productId = product.id " +
                    $"WHERE item.id = @id  FOR UPDATE ";
                var parameters = new { id };
                var data = await connection.QueryFirstOrDefaultAsync<QuotationItem>(query, parameters);
                return data;
        }

@generik0
Copy link

generik0 commented Dec 12, 2016

Workaround :-(



public class Foo
{
 private readonly ISession _session;
 public Foo(ISession session)
 {
    _session=session;
 }
 public async void DoSomething ()
 {
   var quotation = await GetIdAsync(1, _session);
   var somethingElse = await DoBar(1, _session);

  return quotation.Value + somethingElse.Value
 }

 public Task<QuotationItem> GetIdAsync( int id, ISession session)
 {
        return Task.Run(() => return session.Get(new QuotationItem{Id = id}, statement =>
                statement.Incluce<Product>(join=>join.InnerJoin()););
 }
}

@GroundZero
Copy link

@generik0 Please mark It as 'Workaround if you are super retarded and dumb and want you application to suck'. Maybe even underline It.

Do you know that GetId will block and you will block one of the very important threads for the Task Scheduler? You didn't even use long running flag so It's super likely to completly shutdown your application If your application.

For anyone looking at this DO NOT USE IT! It will cause alot of unwanted behvaiour.

@generik0
Copy link

generik0 commented Dec 15, 2016

@GroundZero
Dear ground zero,
Please remember that github is not a social media. You don't need to insult people here. Instead focus on teaching, learning and improving. Hence, you could simply provide a "better" workaround for this bug. In fact you could also fork the code, and fix it. It isn't nice to call people "super retarded", and benefits nobody or anything.

I can see that my example was very "high level" and some of the markdown was messed up. i.e. the "<" and ">". The real meaning of the workaround did not come out well in the example. I have updated a little. I hope it is more pleasing....
In regard to the async method i have followed the examples i could find from MS on how to make an async"able"/await"able" method.: https://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx


internal Task<Bitmap> RenderAsync(
              ImageData data, CancellationToken cancellationToken)
{
    return Task.Run(() =>
    {
        var bmp = new Bitmap(data.Width, data.Height);
        for(int y=0; y&tl;data.Height; y++)
        {
            cancellationToken.ThrowIfCancellationRequested();
            for(int x=0; x&tl;data.Width; x++)
            {
                // render pixel [x,y] into bmp
            }
        }
        return bmp;
    }, cancellationToken);
}

For may example the call to the workaround method would be:
var actual = await _foo.GetIdAsync(1, session);
It shouldn't block, nor cause any application to crash. Yes it will use a thread in the thread pool. But that is it. I have updated workaround example...

Best Regards, your mate, generik0

@generik0
Copy link

@GroundZero Any Comments?

@sachindk1625
Copy link

I'm still facing this issue

An InvalidOperationException is thrown when calling GetAsync().

Exception Text:
Invalid attempt to call FieldCount when reader is closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants