【问题标题】:How can I use SqlDataSource properly with parameters?如何正确使用带有参数的 SqlDataSource?
【发布时间】:2015-03-28 14:08:31
【问题描述】:

这是我正在使用的代码(使用 oracle 开发人员工具):

<asp:SqlDataSource ID="FirstNameSQL" runat="server" ConnectionString="<%$ ConnectionStrings:UserQueries %>" ProviderName="<%$ ConnectionStrings:UserQueries.ProviderName %>" 
        SelectCommand="SELECT &quot;FIRSTNAME&quot; FROM &quot;USERS&quot; WHERE (&quot;USERNAME&quot; = '%?')">
        <SelectParameters>
            <asp:ControlParameter ControlID="UsernameLabel" Name="firstname" PropertyName="Text" Type="String" />
        </SelectParameters>
    </asp:SqlDataSource>

我正在尝试使用标签文本中的参数进行查询。但它不返回任何东西。 可能是我的数据检索方法不对,这里是:

DataView dv4 = (DataView)FirstNameSQL.Select(DataSourceSelectArguments.Empty);
    foreach (DataRow r in dv4.Table.Rows)
    {
        FirstNameLabel.Text = (string)r[0];
    }

有什么建议吗?

【问题讨论】:

  • 你为什么使用SqlDataSource?如果您只想将 Oracle 数据库中的数据提取到 DataView 中,则应该使用 OracleCommand
  • 你的问题部分启发了我写blog post

标签: c# asp.net oracle sqldatasource


【解决方案1】:

您应该使用OracleCommand 类,而不是使用SqlDataSource 以编程方式检索数据。 SqlDataSource 仅应在您直接绑定到 GridView 或其他一些控件时使用。确实,根本不应该使用SqlDataSource,因为在设计合理的系统中,数据访问不应该发生在 UI 层中。

使用official Oracle NuGet package

public static DataTable GetDataTable(OracleCommand command)
{
    DataTable dt = new DataTable();
    using (var connection = GetDefaultOracleConnection())
    {
        command.Connection = connection;
        connection.Open();
        dt.Load(command.ExecuteReader());
    }
    return dt;
}

public static OracleConnection GetDefaultOracleConnection()
{
    return new OracleConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString); //just get a connection string from somewhere
}

//usage
var command = new OracleCommand("select firstname from users where username=:username");
command.Parameters.Add("username", UsernameLabel.Text.Trim());
command.BindByName = true; //incredibly important if more than one parameter
var dt = GetDataTable(command);
DataView dv = dt.AsDataView();

//now get the results. I prefer getting it from the DataTable instead of DataView. Easier to use Linq
if(dt.Rows.Count > 0)
{
    /* Below line requires extra reference to System.Data.DataSetExtensions */
    FirstNameLabel.Text = dt.AsEnumerable().First().Select(r => r.Field<string>("firstname"));
}
else
{
    FirstNameLabel.Text = "not found";
}

以上内容应该已经向您展示了如何以编程方式从数据库中获取数据。但是它仍然没有遵循一个好的架构,因为我们在后面的代码中使用了数据库访问代码。我们后面的代码应该不知道数据库实现细节。所以让我们从头开始,更好地构建它。首先,我们应该定义一个包含用户详细信息的类。我将其命名为ApplicationUser,这样我们就不会与Page.User 属性发生冲突。

public class ApplicationUser
{
    public string Username {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
}

太棒了,现在我们已经为我们的 ApplicationUser 定义了我们需要的东西。但是我们还需要一种从数据库中加载用户的方法。这不应该发生在我们背后的代码或模型中,而应该发生在数据层中。

public class MySiteOracleRepository
{
    private string ConnectionString {get; set;}

    public MySiteOracleRepository(string connectionString)
    {
        ConnectionString = connectionString;
    }

    public ApplicationUser GetUserByUsername(string username)
    {
        OracleCommand command = new OracleCommand("select firstname, lastname, username from users where username=:username");
        DataTable dt = OracleDatabaseHelper.GetDataTable(command, ConnectionString);
        ApplicationUser user = dt.AsEnumerable().Select(r => new ApplicationUser(){
            FirstName = r.Field<string>("firstname"),
            LastName = r.Field<string>("lastname"),
            Username = r.Field<string>("username")
        }).Single();
        return user;
    }
}

这很好。现在我们需要实现OracleDatabaseHelper.GetDataTable(),它将执行对我们数据库的实际访问。

public class OracleDatabaseHelper
{
    public static DataTable GetDataTable(OracleCommand command, string connectionString)
    {
        DataTable dt = new DataTable();
        using (var connection = new OracleConnection(connectionString))
        {
            command.Connection = connection;
            connection.Open();
            dt.Load(command.ExecuteReader());
        }
        return dt;
    }
}

现在,这给了我们什么?一种获取用户信息的简单且可重用的方法。既然我们有了这段代码,我们就不需要每次需要检索用户信息时都重复自己,从而遵循 DRY(不重复自己)的原则。那么让我们看看我们页面背后的代码现在会是什么样子。

private MySiteOracleRepository repo {get; set;}

protected void Page_Load(object sender, EventArgs e)
{
    repo = new MySiteOracleRepository(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);

    if(!IsPostBack)
    {
        LoadUserInfo();
    }
}

protected void LoadUserInfo()
{
    ApplicationUser user = repo.GetUserByUsername(UsernameLabel.Text);
    FirstNameLabel.Text = user.FirstName;
    LastNameLabel.Text = user.LastName;
}

看到我们的页面变得多么简单了吗?请注意,编写一个新的MySiteMySqlRepositoryMySitePostgresRepositoryMySiteMongoRepository 等非常容易,您只需要真正创建一个新课程。您必须修改您的页面以使用不同的存储库类型,但可以使用Dependency Injection 解决该问题。但我不会在这里深入讨论,因为我可能已经对你了解了足够多的新东西。

【讨论】:

  • 我添加了 NuGet 包,但一开始就无法识别 OracleCommand 类,因为它说:找不到类型或命名空间顺便说一句,感谢您的精彩解释
  • @kisbovan93 任何时候遇到这样的错误,这意味着您需要添加一条 using 语句来将命名空间纳入范围。如果您使用的是 Visual Studio,它可以自动完成。右键单击有错误的代码,然后转到解决并在那里选择一个选项。如果你不使用VS,那么我相信你需要添加using Oracle.ManagedDataAccess.Client;
  • 没有 Resolve 这样的选项,当我尝试手动添加引用时,它不接受它。
  • @kisbovan93 您使用的是什么版本的 Visual Studio?
  • 这是视觉工作室 2013 终极版
猜你喜欢
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 2016-09-26
相关资源
最近更新 更多