Commit 92172188 authored by Marc Gravell's avatar Marc Gravell

Make CommandBehavior more configurable; default to...

Make CommandBehavior more configurable; default to SingleRow=allowed,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
parent d03f826d
......@@ -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);
}
......
namespace Dapper
using System;
using System.Data;
namespace Dapper
{
partial class SqlMapper
{
......@@ -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();
......
......@@ -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)]
......@@ -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));
......@@ -1324,25 +1322,10 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
}
}
}
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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment