schotime / NPoco

Simple microORM that maps the results of a query onto a POCO object. Project based on Schotime's branch of PetaPoco
Apache License 2.0
848 stars 302 forks source link

FormatCommand does not work #651

Closed BoboPandora closed 2 years ago

BoboPandora commented 2 years ago

`public class MyDatabase : Database { public MyDatabase(string connectionString) : base(connectionString, DatabaseType.SqlServer2012, SqlClientFactory.Instance) { }

protected override void OnExecutingCommand(DbCommand cmd)
{
    Console.WriteLine(FormatCommand(cmd));
 }

}`

When I used the above code snippet "FormatCommand(cmd)" to record the database query log, the following error message appeared. I know that the problem lies in this function ParameterHelper.SetParameterValue, but I don’t know how to provide it to the author

System.ArgumentException:“No mapping exists from object type NPoco.DatabaseType+FormattedParameter to a known managed provider native type.”

The following is the code snippet I fixed:

`public static void SetParameterValue(DatabaseType dbType, DbParameter p, object value) { if (value == null) { p.Value = DBNull.Value; return; }

        // Give the database type first crack at converting to DB required type
        value = dbType.MapParameterValue(value);

        var dbtypeSet = false;
        var t = value.GetType();
        var underlyingT = Nullable.GetUnderlyingType(t);
        if (t.GetTypeInfo().IsEnum || (underlyingT != null && underlyingT.GetTypeInfo().IsEnum))        // PostgreSQL .NET driver wont cast enum to int
        {
            p.Value = (int)value;
        }
        else if (t == typeof(Guid))
        {
            p.Value = value;
            p.DbType = DbType.Guid;
            p.Size = 40;
            dbtypeSet = true;
        }
        else if (t == typeof(string))
        {
            var strValue = value as string;
            if (strValue == null)
            {
                p.Size = 0;
                p.Value = DBNull.Value;
            }
            else
            {
                // out of memory exception occurs if trying to save more than 4000 characters to SQL Server CE NText column. Set before attempting to set Size, or Size will always max out at 4000
                if (strValue.Length + 1 > 4000 && p.GetType().Name == "SqlCeParameter")
                {
                    p.GetType().GetProperty("SqlDbType").SetValue(p, SqlDbType.NText, null);
                }

                p.Size = Math.Max(strValue.Length + 1, 4000); // Help query plan caching by using common size
                p.Value = value;
            }
        }
        else if (t == typeof(AnsiString))
        {
            var ansistrValue = value as AnsiString;
            if (ansistrValue?.Value == null)
            {
                p.Size = 0;
                p.Value = DBNull.Value;
                p.DbType = DbType.AnsiString;
            }
            else
            {
                // Thanks @DataChomp for pointing out the SQL Server indexing performance hit of using wrong string type on varchar
                p.Size = Math.Max(ansistrValue.Value.Length + 1, 4000);
                p.Value = ansistrValue.Value;
                p.DbType = DbType.AnsiString;
            }
            dbtypeSet = true;
        }
        else if (t == typeof(DatabaseType.FormattedParameter))
        {
            var formattedParamValue = value as DatabaseType.FormattedParameter;
            p.Size = formattedParamValue.Parameter.Size;
            p.Value = formattedParamValue.Parameter.Value;
            p.DbType = formattedParamValue.Parameter.DbType;

            dbtypeSet = true;
        }
        else if (value.GetType().Name == "SqlGeography") //SqlGeography is a CLR Type
        {
            p.GetType().GetProperty("UdtTypeName").SetValue(p, "geography", null); //geography is the equivalent SQL Server Type
            p.Value = value;
        }

        else if (value.GetType().Name == "SqlGeometry") //SqlGeometry is a CLR Type
        {
            p.GetType().GetProperty("UdtTypeName").SetValue(p, "geometry", null); //geography is the equivalent SQL Server Type
            p.Value = value;
        }
        else
        {
            p.Value = value;
        }

        if (!dbtypeSet)
        {
            var dbTypeLookup = dbType.LookupDbType(p.Value.GetTheType(), p.ParameterName);
            if (dbTypeLookup.HasValue)
            {
                p.DbType = dbTypeLookup.Value;
            }
        }
    }`
schotime commented 2 years ago

Push the formatted command into your own object and save that rather than the raw formatted command.