문제

I implemented a custom DbProviderFactory which returned the SqlX types except I added the following logic to CreateCommand

public override DbCommand CreateCommand()
{
    var cmd = new SqlCommand();
    if (CommandCreated != null)
        CommandCreated(cmd, EventArgs.Empty);
    cmd.StatementCompleted += cmd_StatementCompleted;
    return cmd;
}

void cmd_StatementCompleted(object sender, StatementCompletedEventArgs e)
{
    if (StatementCompleted != null)
        StatementCompleted(sender, e);
}

I did this so I could track whenever a SqlDataSource created a command and then when it finished to log all SqlCalls (without needing Sql Profiler up). This worked, however after I implemented this I got an exception with the following SqlDataSource

<asp:SqlDataSource ProviderName="MyProvider" ID="SqlDataSource1" 
    runat="server" ConnectionString="<%$ ConnectionStrings:default %>"
    SelectCommandType="StoredProcedure"
    SelectCommand="dbo.GetX" 
    OnSelecting="SqlDataSource1_Selecting">
    <SelectParameters>
      <asp:Parameter Name="x_id" Type="Byte"/>
    </SelectParameters>
</asp:SqlDataSource>

and this in the code behind.

protected void SqlDataSource1_Selecting(object sender, SqlDataSourceCommandEventArgs e)
{
    e.Command.Parameters["@x_id"].Value = "something else";
}

The error being thrown was that the SqlParameter "@x_id" doesn't exist, even though this worked with the standard SqlClientFactory. When using the debugger it showed that there was 1 parameter in the collection x_id when using MyProvider, and @x_id when using the default provider.

Is there some reason for this and is there some way I can get the @'s added automatically or should I just make sure the code-behind and the SqlDataSource agree on whether there is an @ or not.
The Stored Procedure still works without the '@' sign and luckily I don't do this direct manipulation of the Parameters collection much but I would like to know why this happens in the first place.

Thanks for the help.

도움이 되었습니까?

해결책

After digging more I found the following in the Source of SqlDataSourceView

protected virtual string ParameterPrefix
{
  get
  {
    if (!string.IsNullOrEmpty(this._owner.ProviderName) && !string.Equals(this._owner.ProviderName, "System.Data.SqlClient", StringComparison.OrdinalIgnoreCase))
    {
      return string.Empty;
    }
    return "@";
  }
}

and so when using your own Provider it doesn't match the expected Provider name and so it just returns string.Empty. If you need to do this then you will have to subclass SqlDataSource and SqlDataSourceView

public class MySqlDataSource : SqlDataSource
{
    protected override SqlDataSourceView CreateDataSourceView(string viewName)
    {
        return new MySqlDataSourceView(this, viewName, this.Context);
    }
}

public class MySqlDataSourceView : SqlDataSourceView
{
    private MySqlDataSource _owner;
    public MySqlDataSourceView(IPSqlDataSource owner, string name, System.Web.HttpContext context)
        : base(owner, name, context)
    {
        _owner = owner;
    }

    protected override string ParameterPrefix
    {
        get
        {
            if (!string.IsNullOrEmpty(this._owner.ProviderName) && !string.Equals(this._owner.ProviderName, "MyProvider", StringComparison.OrdinalIgnoreCase))
            {
                return base.ParameterPrefix;
            }
            return "@";
        }
    }

}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top