Domanda

Ho implementato un DbProviderFactory personalizzato che ha restituito i tipi SqlX tranne ho aggiunto la seguente logica per 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);
}

Ho fatto questo in modo da poter tenere traccia di ogni volta che un SqlDataSource creato un comando e poi quando è finito per registrare tutte le SqlCalls (senza bisogno di SQL Profiler su). Questo ha funzionato, ma dopo ho realizzato questo ho ottenuto un'eccezione con il seguente 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>

e questo nel codice dietro.

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

L'errore di essere gettato era che lo SqlParameter "@x_id" non esiste, anche se questo ha lavorato con lo SqlClientFactory standard. Quando si utilizza il debugger ha dimostrato che non vi era 1 parametro nel x_id collezione quando si utilizzano MyProvider, e @x_id quando si utilizza il provider predefinito.

C'è qualche motivo per questo e c'è un modo posso ottenere il @ 's aggiunto automaticamente o devo solo assicurarsi che il code-behind e la SqlDataSource d'accordo su se vi sia un @ oppure no.
La stored procedure funziona ancora senza il segno '@' e per fortuna non faccio questa manipolazione diretta della collezione Parameters molto, ma vorrei sapere perché questo accade, in primo luogo.

Grazie per l'aiuto.

È stato utile?

Soluzione

Dopo aver scavato più ho trovato quanto segue nella Fonte di 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 "@";
  }
}

e così quando si utilizza il proprio provider non corrisponde il nome del provider previsto e quindi restituisce solo string.Empty. Se hai bisogno di fare questo, allora si dovrà sottoclasse SqlDataSource e 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 "@";
        }
    }

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top