UpdateCommand参数值始终为字符串

时间:2017-04-07 13:26:28

标签: c# webforms

我正在尝试使用gridview和SQLDataSource控件更新我的应用程序中的购物车,我正在尝试设置更新命令参数,以便我可以将值发送到我的SQL存储过程,但它不断抛出异常说它无法从nvarchar转换为字符串。

鉴于以下代码;

 ProductsDataSource.UpdateParameters.Add("Description", row.Cells[2].Text);

似乎这个方法不会接受除String以外的任何东西,因为它是第二个参数,那么如何将其转换为其他值以传递给我的参数呢?

我已经尝试过这样的事情;

 int productID = int.Parse(row.Cells[1].Text);

但由于第二个参数HAS有一个字符串参数,我无法将其插入到我的数据库中(抱怨它不能隐式转换为字符串!)

3 个答案:

答案 0 :(得分:2)

我认为我不会直接回答你的代码无法正常工作的原因。即使您使用SqlDataSource修正了错误,我认为从长远来看继续使用也是不错的。使用SqlDataSource作为网页上的控件会在您的UI图层中显示数据库代码。这非常混乱,我们尽量避免使用现代应用程序。 SqlDataSource还鼓励使用魔术字符串,而不是使用强类型模型对象。

更好的选择是完全抛弃SqlDataSource并直接使用ADO.NET(可能通过某些微观ORM,例如Dapper)。我们也可以将这个逻辑移动到它自己的类中,并遵循存储库模式。该类最好放在应用程序引用的单独的类库中,然后您可以重用其他应用程序中的类。我个人经常有一个控制台应用程序,这样我就可以测试我的存储库中的一些内容而无需通过网站。

不是让您的网站直接依赖此存储库类,而是通常使用接口。这使我们的网站无需直接依赖于数据库逻辑的实现方式。通常这与依赖注入相结合,但这个帖子的主题太大了。我强烈建议您查看关于依赖注入的this excellent video

所以,这是我们的界面:

public interface IProductRepository
{
    Product GetProductById(int id);

    void UpdateProduct(Product product);

    List<Product> GetAllProducts();
}

现在实际实施:

public class SqlServerProductRepository: IProductRepository
{
    private readonly string _connectionString;

    public ProductRepository(string connectionString)
    {
        _connectionString = connectionString;
    }

    public Product GetProductById(int id)
    {
        using(var connection = new SqlConnection(_connectionString))
        {
            //QuerySingle is an extension method from Dapper
            return connection.QuerySingle<Product>("select Name, Description, Id from Products where Id = @Id", new {Id = id});
        }
    }

    public void UpdateProduct(Product product)
    {
        using(var connection = new SqlConnection(_connectionString))
        {
            //Execute is an extension method from Dapper
            connection.Execute("update Products set Name = @Name, Description = @Description where Id = @Id", product);
        }
    }

    public List<Product> GetAllProducts()
    {
        using(var connection = new SqlConnection(_connectionString))
        {
            //Query is an extension method from Dapper
            //You'd likely want to implement filters/paging etc in a real world app
            return connection.Query<Product>("select Name, Description, Id from Products").AsList();
        }
    }
}

如果你没有现有的模特课,你需要一个模特课:

public class Product
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}

现在,您网站上的代码变得更加简单:

//you can remove the direct reference to SqlServerProductRepository
//via Dependency Injection, not shown here
IProductRepository productRepository = new SqlServerProductRepository(connectionString);

var product = productRepository.GetProductById(1);
product.Description = "Updated Description";
productRepository.UpdateProduct(product);

ProductsGridView.DataSource = productRepository.GetAllProducts();
ProductsGridView.DataBind();

您可以采用其他方式来实施存储库,例如在调用SaveChanges之前进行批量更改,但这是一个基本实现。

在界面后面抽象数据库交互的另一个好处是,您可以尝试不同的实现,而无需更改整个网站。想尝试Entity Framework吗?创建一个实现EntityFrameworkProductRepository的新IProductRepository。如果要完全切换数据库怎么办? SqlLite是免费且轻量级的,适用于小型应用程序。创建一个新的SqlLiteProductRepository

答案 1 :(得分:1)

您可以在标记上指定参数类型..

<UpdateParameters >
  <asp:Parameter Name="paramName" DbType="String" Type="String" />

你可以在背后的代码上设置值。

ProductsDataSource.UpdateParameters["paramName"].DefaultValue = "parameter value";

或者您可以使用Add方法的重载而不使用标记定义。

SqlDataSource1.UpdateParameters.Add("paramName", DbType.String, "parameter value");

答案 2 :(得分:-3)

尝试 string productID =(string)(row.Cells [1] .Text)