25

So I'm trying to use Dapper.net and I'm liking it. What I'm not liking is when I try to batch-insert entities and I get the following error thrown:

Invalid type owner for DynamicMethod.

at System.Reflection.Emit.DynamicMethod.Init(String name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] signature, Type owner, Module m, Boolean skipVisibility, Boolean transparentMethod, StackCrawlMark& stackMark) at System.Reflection.Emit.DynamicMethod..ctor(String name, Type returnType, Type[] parameterTypes, Type owner, Boolean skipVisibility) at Dapper.SqlMapper.CreateParamInfoGenerator(Identity identity, Boolean checkForDuplicates, Boolean removeUnused, IList1 literals) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 3033 at Dapper.SqlMapper.GetCacheInfo(Identity identity, Object exampleParameters, Boolean addToCache) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 2138 at Dapper.SqlMapper.<QueryImpl>d__611.MoveNext() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 1578 at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable1 commandTimeout, Nullable1 commandType) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 1479 at Dapper.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable1 commandTimeout, Nullable1 commandType) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 1418 at NinjaEvaluation.Data.Database.DapperWrapper.<>c__DisplayClass41.b__3(SqlConnection sqlConnection, SqlTransaction transaction) in c:\Projects\InHouse\ninjaevaluation\NinjaEvaluation\NinjaEvaluation.Data\Database\DapperWrapper.cs:line 52 at NinjaEvaluation.Data.Database.DapperWrapper.Invoke(Action`2 action) in c:\Projects\InHouse\ninjaevaluation\NinjaEvaluation\NinjaEvaluation.Data\Database\DapperWrapper.cs:line 68

This happens in a completely normal situation when I run my query like this:

        string sql = @" INSERT INTO XXX
                        (XXXId, AnotherId, ThirdId, Value, Comment)
                        VALUES
                        (@XXXId, @AnotherId, @ThirdId, @Value, @Comment)";

        var parameters = command
            .MyModels
            .Select(model => new
            {
                XXXId= model.XXXId,
                AnotherId= model.AnotherId,
                ThirdId= model.ThirdId,
                Value = model.Value,
                Comment = model.Comment
            })
            .ToArray();

...

sqlConnection.Query(sql, parameters, commandType: commandType, transaction: transaction)

I found the following SO-thread started by someone having the same problem BUT the issue there seems to have been the .NET version (3.5) but I'm running .NET 4.5 and I can't figure out what the problem is.

Any suggestions?

2
  • I wonder - is this a restricted trust environment? Or regular .net with nothing special? Commented May 25, 2015 at 17:08
  • Regular local environment. No restrictions at all. Commented May 26, 2015 at 6:24

2 Answers 2

46

I ran into this error when using an interface instead of the class:

Query<MyObject> worked, while Query<IMyObject> did not

Sign up to request clarification or add additional context in comments.

2 Comments

Same as me I ran into this error when using an interface instead of the class: Query<MyObject> worked, while Query<IMyObject> did not. you should ensure that you use the class type on the return value for the executing command, not Interface.
My issue was basically the same, but when trying to retrieve a list of objects, I mistakenly wrote Query<IEnumerable<MyObject>> instead of Query<MyObject>
18

It fails because this scenario using Query[<T>] isn't expecting an array / sequence of parameters. The Execute call-path does expect this, and unrolls the data automatically, executing the SQL once per item - but this isn't the case for Query[<T>], so it tries to create the dynamic method bound to the array (in your case), which isn't allowed. The code should probably detect this much earlier, and just say "nope, that isn't allowed".

You probably want to change your .ToArray() to .Single().

This will be clearer after the next build; the following passes:

    public void SO30435185_InvalidTypeOwner()
    {
        try {
            // not shown for brevity: something very similar to your code
            Assert.Fail();
        } catch(InvalidOperationException ex)
        {
            ex.Message.IsEqualTo("An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context");
        }
    }

4 Comments

I should've used Execute :)
@Maffelu heh, or that ;p
Is this a shortcoming of Dapper, or does it logically not make sense to query with a sequence of parameters? This question is interested in selecting the IDs of inserted rows, which is not possible in the current state of Dapper. This question Implies it used to work - the first snippet - or is their error related to this? To me it would seem that if Execute can handle a sequence of parameters, Query should be able to as well. The best workaround I can come up with involves 4 separate queries, which isn't ideal
@Rob well, where the loop appears isn't going to make a huge difference to the actual operations; yes, we could make Query work with a sequence and essentially concatenate the results, but would it be any clearer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.