11

I'm using Dapper and Dapper.Contrib in an MVC5 c# environment and sometimes (!) when I deploy the production site I get errors stating:

GetAll<T> only supports an entity with a single [Key] or [ExplicitKey] property at Dapper.Contrib.Extensions.SqlMapperExtensions.GetSingleKey[T](String method) at Dapper.Contrib.Extensions.SqlMapperExtensions.GetAllAsync[T](IDbConnection connection, IDbTransaction transaction, Nullable`1 commandTimeout)

This only happens about one every third deploy though.

I'm suspecting that somehow Dapper.Contrib notices my primary key automatically, as it's named "Id", but I've decorated it with [ExplicitKey] (it's a GUID) and perhaps those attributes clash. Perhaps it's something entirely different...

Any idea on how to get around this problem, other than possibly renaming my primary key?

A piece from the model in question:

[Table("Tasks")]
public class TasksModel
{
    [ExplicitKey]
    public Guid Id { get; set; }

...
Mackan
  • 6,200
  • 2
  • 25
  • 45
  • I'm having the exact same problem, the only difference is that we have [ExplicitKey] SqlHierarchyId as primary key. Did you manage to find a workaround for this, or pinpoint the cause of it? (I'm thinking about using QueryAsync from vanilla Dapper instead of GetAsync, which works, but doesn't solve the issue with Contrib...) Thanks! – Darth Veyda May 15 '18 at 05:55
  • @DarthVeyda Afraid I didn't find either cause or a good solution (as my issue was intermittent). I don't experience the problem any more, and I think I just switched the _GetAll()_ for the offending model to regular dapper. I still use _contrib_ without issues for other similar classes. – Mackan May 15 '18 at 06:46
  • 4
    I just saw this issue today for the first time on our production web api system. The only resolution was to restart the server. If it happens again, I'll rip dapper.contrib out of our code. I've looked at the source code for dapper.contrib, and the only way this issue can occur is if the internal cache it builds somehow thinks there's either 2 [Key] or 2 [ExplicitKey] or 1 of each on the offending type. And I'm certain, as the OP was, that this is not the case. So the internal cache mechanism seems to have a bug somewhere. – Mr. T Jan 21 '19 at 20:48

1 Answers1

1

I think this is related to the name of the property, "id". The following is from the KeyCache building code in Dapper/SqlMapperExtensions.cs, when there are no properties with the [Key] attribute.

var idProp = allProperties.Find(p => string.Equals(p.Name, "id", StringComparison.CurrentCultureIgnoreCase));

In your case, you get both an ExplicitKey (by decorating your key with [ExplicitKey] in your model), and a Key (by default as this property is called Id). Unless you can change the DB column name, I would use regular Dapper.

Srdja V
  • 11
  • 1
  • Thanks for your input - your guess is the same as I made in my original post. But I've yet to see some evidence of the problem or a solution _other than renaming my primary key_ (also stated in the original post). I have looked at Contribs source code and I cannot find the problem. This would fit better as a comment than an answer i.m.o. – Mackan Mar 28 '19 at 14:17
  • Dapper.Contrib looks for [Key], if nothing found gets the field named "id". Check https://github.com/StackExchange/Dapper/blob/master/Dapper.Contrib/SqlMapperExtensions.cs in function ```private static List KeyPropertiesCache(Type type)```: ```var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)).ToList(); if (keyProperties.Count == 0) { var idProp = allProperties.Find(p => string.Equals(p.Name, "id", StringComparison.CurrentCultureIgnoreCase)); ``` – Srdja V Mar 29 '19 at 15:30
  • So, you get the same property in the _KeyPropertiesCache_ because it is called **Id**, and in the _ExplicitKeyPropertiesCache_ because it is decorated with ```[ExplicitKey]```. No attributes clash, but the same property ends up both as a Key (DB generated) and ExplicitKey (not generated by the DB) and Dapper.Contrib is confused as what you want. – Srdja V Mar 29 '19 at 15:39
  • When I followed the code a couple of months ago, attribute _ExplicitKey_ did not follow that same path. But this was a while ago and I might remember wrong. I'll have another look, and if you are right award you accordingly :) thanks – Mackan Mar 29 '19 at 15:46