Skip to content

Commit

Permalink
Make CommandBehavior more configurable; default to SingleRow=allowed,…
Browse files Browse the repository at this point in the history
…SingleResult=disallowed - but expose options; this fixes issues like #563 automatically, and allows the performance aspect  of #554 to be fixed via a global setting
  • Loading branch information
mgravell committed Sep 8, 2016
1 parent d03f826 commit 9217218
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Dapper/SqlMapper.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public static Task<T> QuerySingleOrDefaultAsync<T>(this IDbConnection cnn, Comma
private static Task<DbDataReader> ExecuteReaderWithFlagsFallbackAsync(DbCommand cmd, bool wasClosed, CommandBehavior behavior, CancellationToken cancellationToken)
{
var task = cmd.ExecuteReaderAsync(GetBehavior(wasClosed, behavior), cancellationToken);
if (task.Status == TaskStatus.Faulted && DisableCommandBehaviorOptimizations(behavior, task.Exception.InnerException))
if (task.Status == TaskStatus.Faulted && Settings.DisableCommandBehaviorOptimizations(behavior, task.Exception.InnerException))
{ // we can retry; this time it will have different flags
task = cmd.ExecuteReaderAsync(GetBehavior(wasClosed, behavior), cancellationToken);
}
Expand Down
44 changes: 43 additions & 1 deletion Dapper/SqlMapper.Settings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Dapper
using System;
using System.Data;

namespace Dapper
{
partial class SqlMapper
{
Expand All @@ -7,6 +10,45 @@ partial class SqlMapper
/// </summary>
public static class Settings
{
// disable single result by default; prevents errors AFTER the select being detected properly
const CommandBehavior DefaultAllowedCommandBehaviors = ~CommandBehavior.SingleResult;
internal static CommandBehavior AllowedCommandBehaviors { get; private set; } = DefaultAllowedCommandBehaviors;
private static void SetAllowedCommandBehaviors(CommandBehavior behavior, bool enabled)
{
if (enabled) AllowedCommandBehaviors |= behavior;
else AllowedCommandBehaviors &= ~behavior;
}
/// <summary>
/// Gets or sets whether dapper should use the CommandBehavior.SingleResult optimization
/// </summary>
public static bool UseSingleResultOptimization
{
get { return (AllowedCommandBehaviors & CommandBehavior.SingleResult) != 0; }
set { SetAllowedCommandBehaviors(CommandBehavior.SingleResult, value); }
}
/// <summary>
/// Gets or sets whether dapper should use the CommandBehavior.SingleRow optimization
/// </summary>
public static bool UseSingleRowOptimization
{
get { return (AllowedCommandBehaviors & CommandBehavior.SingleRow) != 0; }
set { SetAllowedCommandBehaviors(CommandBehavior.SingleRow, value); }
}
internal static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex)
{
if (AllowedCommandBehaviors == DefaultAllowedCommandBehaviors
&& (behavior & (CommandBehavior.SingleResult | CommandBehavior.SingleRow)) != 0)
{
if (ex.Message.Contains(nameof(CommandBehavior.SingleResult))
|| ex.Message.Contains(nameof(CommandBehavior.SingleRow)))
{ // some providers just just allow these, so: try again without them and stop issuing them
SetAllowedCommandBehaviors(CommandBehavior.SingleResult | CommandBehavior.SingleRow, false);
return true;
}
}
return false;
}

static Settings()
{
SetDefaults();
Expand Down
25 changes: 4 additions & 21 deletions Dapper/SqlMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,7 @@ private static void ResetTypeHandlers(bool clone)
#endif
AddTypeHandlerImpl(typeof(XmlDocument), new XmlDocumentHandler(), clone);
AddTypeHandlerImpl(typeof(XDocument), new XDocumentHandler(), clone);
AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone);

allowedCommandBehaviors = DefaultAllowedCommandBehaviors;
AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone);
}
#if !COREFX
[MethodImpl(MethodImplOptions.NoInlining)]
Expand Down Expand Up @@ -912,7 +910,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w
}
catch (ArgumentException ex)
{ // thanks, Sqlite!
if (DisableCommandBehaviorOptimizations(behavior, ex))
if (Settings.DisableCommandBehaviorOptimizations(behavior, ex))
{
// we can retry; this time it will have different flags
return cmd.ExecuteReader(GetBehavior(wasClosed, behavior));
Expand Down Expand Up @@ -1324,25 +1322,10 @@ static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFift
}
}
}
const CommandBehavior DefaultAllowedCommandBehaviors = ~((CommandBehavior)0);
static CommandBehavior allowedCommandBehaviors = DefaultAllowedCommandBehaviors;
private static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex)
{
if(allowedCommandBehaviors == DefaultAllowedCommandBehaviors
&& (behavior & (CommandBehavior.SingleResult | CommandBehavior.SingleRow)) != 0)
{
if (ex.Message.Contains(nameof(CommandBehavior.SingleResult))
|| ex.Message.Contains(nameof(CommandBehavior.SingleRow)))
{ // some providers just just allow these, so: try again without them and stop issuing them
allowedCommandBehaviors = ~(CommandBehavior.SingleResult | CommandBehavior.SingleRow);
return true;
}
}
return false;
}

private static CommandBehavior GetBehavior(bool close, CommandBehavior @default)
{
return (close ? (@default | CommandBehavior.CloseConnection) : @default) & allowedCommandBehaviors;
return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors;
}
static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{
Expand Down

0 comments on commit 9217218

Please sign in to comment.