【问题标题】:UpdateCommand Parameter value always a stringUpdateCommand 参数值始终为字符串
【发布时间】:2017-04-07 22:32:37
【问题描述】:

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

给定以下代码;

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

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

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

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

但是由于第二个参数必须有一个字符串参数,我不能将它插入我的数据库(抱怨它不能隐式转换为字符串!)

【问题讨论】:

  • 你为什么首先使用SqlDataSource?为什么不坚持简单的 ADO.NET 并使用 SqlConnection 和 SqlCommand?
  • 使用SqlDataSource 一点意义都没有!现在您已经将数据库代码散布到您的 UI 层中。这不好!相反,您的数据库操作应该封装到一个单独的类中(通常放在一个单独的类库中),并且您的页面应该获取该类的一个实例以执行与数据库的任何交互。您应该查看“存储库模式”。
  • 是否有另一个重载允许您在 UpdateParameters.Add( 中指定类型

标签: c# webforms


【解决方案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】:

    与其直接回答为什么您的代码不起作用,我想我会提出一个替代方案。即使你用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 之前对其进行批量更改等,但这是一个基本的实现。

    将数据库交互抽象化为接口的另一个优点是,您可以尝试不同的实现,而无需更改整个网站。想尝试实体框架?创建一个实现IProductRepository 的新EntityFrameworkProductRepository。如果你想完全切换数据库怎么办? SqlLite 是免费且轻量级的,适用于小型应用程序。创建一个新的SqlLiteProductRepository。

    【讨论】:

    • 谢谢,我会调查的 :)
    【解决方案3】:

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

    【讨论】:

    • 将字符串转换为字符串?
    • 用调试器看看什么返回 row.Cells [1] .Text 如果返回的字符串不需要转换为字符串,则需要转换为字符串
    猜你喜欢
    • 1970-01-01
    • 2012-06-15
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 2022-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多