sqltype IsDBNull

本文探讨了.NET和SQL在decimal、datetime、String三种数据类型上的兼容性问题,强调了在获取这些数据时避免数据截断的重要性。同时指出SQL中的所有数据类型可为空,而.NET中的引用类型可为空。

原文地址:http://www.cnblogs.com/qianyz/archive/2010/10/11/1848148.html


从数据库读取数据的时候一定要注意数据的类型兼容性

就.NET和SQL 来说,数据的兼容性有三个数据类型需要注意, decaimal SQL中的范围比.NET中的要大

  datetime .NET中的要比SQL中的精度高, String   .NET中和SQL中的长度不一样,因此在获取和这三

 个数据类型相关的数据的时候,一定要注意不要被数据截断。

SQL中的所有数据类型都是可空的,而.NET中只有引用类型是可空的,

SQL中的数据类型有另外有一个数据字段,有一个标志字段,如果这个字段为0,就表示这个值为NULL。

否则为非空。


<think>由于数据库SQLServer2012,它不支持STRING_AGG函数(该函数在SQLServer2017引入)。因此,我们需要使用兼容的方法,比如使用FORXMLPATH或自定义函数来聚合字符串。此外,根据之前的需求,我们需要为商品详情页提供后端代码,包括加载商品详情、加载相关商品、记录访问日志、添加到购物车等功能。我们将调整之前的代码,使其兼容SQLServer2012。主要改动在字符串聚合部分,我们将使用FORXMLPATH方法或自定义函数(在之前的步骤中已经给出了自定义函数的方案,这里我们选择在应用层使用FORXMLPATH或者使用视图中的自定义函数)。为了保持代码的清晰和可维护性,我们可以在数据库中创建一个标量值函数(如之前所述)来获取商品的变体名称列表。但是,为了减少数据库函数的依赖,我们也可以在代码中使用两个独立的查询:一个获取商品基本信息,另一个获取商品的所有变体,然后在代码中拼接字符串。但是,考虑到在商品详情页中,我们只需要显示一个逗号分隔的变体字符串,且变体数据量不大,我们可以在一次查询中完成,使用子查询和FORXMLPATH。然而,由于在视图中使用FORXMLPATH可能会使视图变得复杂,并且可能影响性能,我们选择在加载商品详情的存储过程中使用FORXMLPATH,或者在后端代码中分别查询。但根据之前的代码结构,我们是在LoadProductDetails方法中直接执行一个查询。因此,我们可以修改这个查询,使用FORXMLPATH来获取变体字符串。考虑到后续可能在其他地方也需要同样的聚合,我们可以在数据库中创建一个函数,这样更有利于重用。我们采用以下方案:1.数据库中创建函数dbo.GetProductVariants,用于获取指定商品的变体名称列表(逗号分隔)。2.在查询商品详情时,使用这个函数来获取变体字符串。如果不想创建函数,也可以在查询中直接使用子查询,但是这样会使查询语句变得冗长。步骤:1.创建函数dbo.GetProductVariants2.修改商品详情查询,使用这个函数但是,请注意SQLServer2012不支持CREATEORALTER,所以我们需要判断函数是否存在,如果存在则删除再创建。另外,由于SQLServer2012的版本限制,我们还需要注意其他语法兼容性。下面我们提供完整的后端代码,并假设数据库已经按照之前的脚本创建了表,并且创建了函数dbo.GetProductVariants。我们回顾一下函数dbo.GetProductVariants的代码:```sqlIFOBJECT_ID('dbo.GetProductVariants','FN')ISNOTNULLDROPFUNCTIONdbo.GetProductVariants;GOCREATEFUNCTIONdbo.GetProductVariants(@ProductIDINT)RETURNSNVARCHAR(MAX)ASBEGINDECLARE@ResultNVARCHAR(MAX)='';SELECT@Result=@Result+VariantName+','FROMProductVariantsWHEREProductID=@ProductID;--移除最后一个逗号和空格IFLEN(@Result)>0SET@Result=LEFT(@Result,LEN(@Result)-1);RETURN@Result;END;GO```然后,我们修改LoadProductDetails方法中的查询,使用这个函数。另外,由于在SQLServer2012中,我们可能没有Brands表,之前的视图脚本中包含了Brands表,如果不存在,我们可以去掉。或者,如果我们的数据库中没有Brands表,那么我们需要调整查询。根据之前的需求,我们假设数据库中有以下表:-Products-Categories-ProductImages-ProductVariants-其他日志表等由于我们之前提供的数据库脚本中包含了这些表,这里我们假设数据库已经建立。下面是完整的WebForm3.aspx.cs代码,适配SQLServer2012:注意:我们将在代码中使用dbo.GetProductVariants函数。如果因权限问题无法创建函数,则可能需要调整方案。我们将之前LoadProductDetails方法中的查询修改为使用函数获取变体。同时,我们还需要处理一些错误情况,例如函数不存在等。为了简化,我们假设函数已经存在。完整的后端代码(WebForm3.aspx.cs)如下:</think> # SQL Server 2012 兼容的后端代码实现 以下是完整兼容 SQL Server 2012 的后端代码实现,解决了 `STRING_AGG` 不可用问题,同时优化了整体架构: ```csharp using System; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Web; using System.Web.UI; using System.Web.Configuration; using System.Collections.Generic; using System.Diagnostics; namespace WebApplication1 { public partial class ProductDetail : Page { private int currentProductId; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (!ValidateRequestParameters()) { Response.Redirect("~/Default.aspx"); return; } LoadProductDetails(currentProductId); LoadRelatedProducts(currentProductId); LogPageVisit(currentProductId); } } /// <summary> /// 验证请求参数并获取商品ID /// </summary> private bool ValidateRequestParameters() { if (!int.TryParse(Request.QueryString["id"], out currentProductId)) { ShowErrorMessage("无效的商品ID参数"); return false; } if (currentProductId <= 0) { ShowErrorMessage("商品ID必须为正整数"); return false; } return true; } /// <summary> /// 加载商品详情 - 兼容SQL Server 2012 /// </summary> private void LoadProductDetails(int productId) { string connString = GetConnectionString(); if (string.IsNullOrEmpty(connString)) { ShowErrorMessage("数据库连接配置错误"); return; } try { using (var conn = new SqlConnection(connString)) { // 使用XML PATH替代STRING_AGG string query = @" SELECT p.ProductID, p.ProductName, p.Subtitle, p.Description, p.Price, p.DiscountPrice, p.StockQuantity, p.CategoryID, p.Rating, p.ReviewCount, c.CategoryName, pi.ImagePath, Variants = STUFF(( SELECT ', ' + pv.VariantName FROM ProductVariants pv WHERE pv.ProductID = p.ProductID FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') FROM Products p INNER JOIN Categories c ON p.CategoryID = c.CategoryID LEFT JOIN ProductImages pi ON p.ProductID = pi.ProductID AND pi.IsDefault = 1 WHERE p.ProductID = @ProductID"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@ProductID", productId); conn.Open(); using (SqlDataReader reader = cmd.ExecuteReader()) { if (reader.Read()) { DisplayProductDetails(reader); productContainer.Visible = true; } else { ShowErrorMessage("找不到指定的商品"); } } } } } catch (SqlException sqlEx) { LogError($"SQL错误: {sqlEx.Message}", sqlEx); ShowErrorMessage("数据库连接错误,请稍后再试"); } catch (Exception ex) { LogError($"加载商品信息失败: {ex.Message}", ex); ShowErrorMessage("加载商品信息时出错"); } } /// <summary> /// 显示商品详情到页面控件 /// </summary> private void DisplayProductDetails(SqlDataReader reader) { // 基本信息 ltProductName.Text = HttpUtility.HtmlEncode(reader["ProductName"].ToString()); ltSubtitle.Text = HttpUtility.HtmlEncode(reader["Subtitle"].ToString()); ltCategory.Text = HttpUtility.HtmlEncode(reader["CategoryName"].ToString()); // 价格 decimal price = Convert.ToDecimal(reader["Price"]); ltPrice.Text = price.ToString("C"); if (!Convert.IsDBNull(reader["DiscountPrice"]) && price > Convert.ToDecimal(reader["DiscountPrice"])) { decimal discountPrice = Convert.ToDecimal(reader["DiscountPrice"]); ltDiscountPrice.Text = discountPrice.ToString("C"); ltSavings.Text = $"节省 {(price - discountPrice).ToString("C")}"; } // 库存 int stock = Convert.ToInt32(reader["StockQuantity"]); ltStock.Text = stock.ToString(); ltStockStatus.Text = stock > 0 ? "<span class='text-success'><i class='bi bi-check-circle'></i>有货</span>" : "<span class='text-danger'><i class='bi bi-x-circle'></i>缺货</span>"; // 评分 decimal rating = Convert.ToDecimal(reader["Rating"]); ltRating.Text = GenerateRatingStars(rating); ltReviewCount.Text = reader["ReviewCount"].ToString(); // 图片 string imagePath = reader["ImagePath"]?.ToString() ?? ""; imgProduct.ImageUrl = !string.IsNullOrEmpty(imagePath) ? imagePath : "~/Images/default-product.jpg"; // 描述 ltDescription.Text = HttpUtility.HtmlEncode(reader["Description"].ToString()); // 商品型号 if (!reader.IsDBNull(reader.GetOrdinal("Variants"))) { string variants = reader["Variants"].ToString(); if (!string.IsNullOrWhiteSpace(variants)) { ltAvailableVariants.Text = variants; variantSelector.Visible = true; } } } /// <summary> /// 生成评分星星HTML /// </summary> private string GenerateRatingStars(decimal rating) { int fullStars = (int)rating; bool hasHalfStar = (rating - fullStars) >= 0.5M; int emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); return $@" {string.Concat(Enumerable.Repeat("<i class='bi bi-star-fill text-warning'></i>", fullStars))} {(hasHalfStar ? "<i class='bi bi-star-half text-warning'></i>" : "")} {string.Concat(Enumerable.Repeat("<i class='bi bi-star text-warning'></i>", emptyStars))} <span class='ms-2'>{rating:F1}</span>"; } /// <summary> /// 加载相关商品 - SQL Server 2012兼容 /// </summary> private void LoadRelatedProducts(int productId) { string connString = GetConnectionString(); if (string.IsNullOrEmpty(connString)) return; try { using (var conn = new SqlConnection(connString)) { // 获取同类别的前4个相关商品 string query = @" SELECT TOP 4 p.ProductID, p.ProductName, p.Price, (SELECT TOP 1 ImagePath FROM ProductImages WHERE ProductID = p.ProductID ORDER BY IsDefault DESC) AS ImagePath FROM Products p WHERE p.CategoryID = ( SELECT CategoryID FROM Products WHERE ProductID = @ProductID ) AND p.ProductID <> @ProductID ORDER BY NEWID()"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@ProductID", productId); conn.Open(); rptRelatedProducts.DataSource = cmd.ExecuteReader(); rptRelatedProducts.DataBind(); } } } catch (Exception ex) { LogError($"加载相关商品失败: {ex.Message}", ex); } } /// <summary> /// 添加到购物车按钮点击事件 /// </summary> protected void btnAddToCart_Click(object sender, EventArgs e) { if (!ValidateRequestParameters()) return; try { // 获取用户选择的型号 string variant = Request.Form["product_variant"]; // 获取数量 int quantity; if (!int.TryParse(txtQuantity.Value, out quantity) || quantity < 1) { quantity = 1; } // 添加到购物车 Cart cart = GetOrCreateCart(); cart.AddItem(currentProductId, quantity, variant); // 更新购物车数量显示 UpdateCartBadge(cart.TotalItems); // 显示成功消息 ClientScript.RegisterStartupScript(GetType(), "AddToCartSuccess", "showToast('success', '商品已添加到购物车!');", true); } catch (Exception ex) { LogError($"添加到购物车失败: {ex.Message}", ex); ClientScript.RegisterStartupScript(GetType(), "AddToCartError", "showToast('error', '添加到购物车失败,请重试');", true); } } /// <summary> /// 记录页面访问 - SQL Server 2012兼容 /// </summary> private void LogPageVisit(int productId) { try { string connString = GetConnectionString(); using (var conn = new SqlConnection(connString)) { string query = @" INSERT INTO ProductVisits (ProductID, UserIP, SessionID, VisitDate) VALUES (@ProductID, @UserIP, @SessionID, GETDATE())"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@ProductID", productId); cmd.Parameters.AddWithValue("@UserIP", GetUserIP()); cmd.Parameters.AddWithValue("@SessionID", Session.SessionID); conn.Open(); cmd.ExecuteNonQuery(); } } } catch (Exception ex) { LogError($"访问日志记录失败: {ex.Message}", ex); } } /// <summary> /// 获取用户购物车 /// </summary> private Cart GetOrCreateCart() { // 持久化到数据库,而不仅仅是Session string sessionId = Session.SessionID; int? userId = Session["UserID"] as int?; string connString = GetConnectionString(); using (var conn = new SqlConnection(connString)) { conn.Open(); return CartManager.GetOrCreateCart(conn, sessionId, userId); } } /// <summary> /// 更新页面购物车徽章显示 /// </summary> private void UpdateCartBadge(int count) { // 查找母版页中的购物车徽章 var cartBadge = Master?.FindControl("cartBadge") as System.Web.UI.HtmlControls.HtmlGenericControl; if (cartBadge != null) { cartBadge.InnerText = count.ToString(); cartBadge.Visible = count > 0; } } /// <summary> /// 获取数据库连接字符串 /// </summary> private string GetConnectionString() { return WebConfigurationManager.ConnectionStrings["DB-NetShops"]?.ConnectionString; } /// <summary> /// 获取用户IP地址 /// </summary> private string GetUserIP() { string ip = Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (string.IsNullOrEmpty(ip)) { ip = Request.ServerVariables["REMOTE_ADDR"]; } else { string[] addresses = ip.Split(','); if (addresses.Length != 0) { return addresses[0]; } } return ip; } /// <summary> /// 显示错误消息 /// </summary> private void ShowErrorMessage(string message) { if (ltErrorMessage != null) { ltErrorMessage.Text = $"<div class='alert alert-danger'>{HttpUtility.HtmlEncode(message)}</div>"; ltErrorMessage.Visible = true; productContainer.Visible = false; } } /// <summary> /// 记录错误日志 /// </summary> private void LogError(string message, Exception ex) { try { string logMessage = $"[{DateTime.Now}] {message}\nException: {ex}\n\n"; System.IO.File.AppendAllText(Server.MapPath("~/App_Data/error.log"), logMessage); // 也可记录到数据库 using (var conn = new SqlConnection(GetConnectionString())) { string query = @" INSERT INTO ErrorLog (Source, Message, StackTrace, LogDate) VALUES (@Source, @Message, @StackTrace, GETDATE())"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@Source", ex.Source); cmd.Parameters.AddWithValue("@Message", ex.Message); cmd.Parameters.AddWithValue("@StackTrace", ex.StackTrace); conn.Open(); cmd.ExecuteNonQuery(); } } } catch { // 文件记录失败时不中断 } } } /// <summary> /// 购物车管理类 /// </summary> public static class CartManager { /// <summary> /// 获取或创建购物车 /// </summary> public static Cart GetOrCreateCart(SqlConnection conn, string sessionId, int? userId) { Cart cart; // 尝试从数据库加载购物车 if (userId.HasValue && userId > 0) { cart = LoadUserCart(conn, userId.Value); } else { cart = LoadSessionCart(conn, sessionId); } // 如果不存在则创建新购物车 if (cart == null) { cart = new Cart(sessionId, userId); SaveCart(conn, cart); } return cart; } /// <summary> /// 从数据库加载用户购物车 /// </summary> private static Cart LoadUserCart(SqlConnection conn, int userId) { string query = @" SELECT ci.ItemID, ci.ProductID, p.ProductName, p.Price, ci.Variant, ci.Quantity FROM ShoppingCart sc INNER JOIN CartItems ci ON sc.CartID = ci.CartID INNER JOIN Products p ON ci.ProductID = p.ProductID WHERE sc.UserID = @UserID"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@UserID", userId); using (var reader = cmd.ExecuteReader()) { if (reader.HasRows) { var cart = new Cart(reader["SessionID"].ToString(), userId); while (reader.Read()) { cart.Items.Add(new CartItem { ItemId = reader.GetInt32(0), ProductId = reader.GetInt32(1), ProductName = reader.GetString(2), Price = reader.GetDecimal(3), Variant = reader["Variant"]?.ToString(), Quantity = reader.GetInt32(5) }); } return cart; } } } return null; } /// <summary> /// 保存购物车到数据库 /// </summary> private static void SaveCart(SqlConnection conn, Cart cart) { // 创建购物车记录 string query = @" INSERT INTO ShoppingCart (SessionID, UserID, CreatedDate) OUTPUT INSERTED.CartID VALUES (@SessionID, @UserID, GETDATE())"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@SessionID", cart.SessionId); cmd.Parameters.AddWithValue("@UserID", (object)cart.UserId ?? DBNull.Value); var cartId = (int)cmd.ExecuteScalar(); cart.CartId = cartId; // 保存购物车项 foreach (var item in cart.Items) { SaveCartItem(conn, cartId, item); } } } /// <summary> /// 保存购物车项 /// </summary> private static void SaveCartItem(SqlConnection conn, int cartId, CartItem item) { string query = @" INSERT INTO CartItems (CartID, ProductID, Variant, Quantity) VALUES (@CartID, @ProductID, @Variant, @Quantity)"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@CartID", cartId); cmd.Parameters.AddWithValue("@ProductID", item.ProductId); cmd.Parameters.AddWithValue("@Variant", (object)item.Variant ?? DBNull.Value); cmd.Parameters.AddWithValue("@Quantity", item.Quantity); cmd.ExecuteNonQuery(); } } } /// <summary> /// 购物车类 /// </summary> public class Cart { public int CartId { get; set; } public string SessionId { get; } public int? UserId { get; } public List<CartItem> Items { get; } = new List<CartItem>(); public int TotalItems => Items.Sum(item => item.Quantity); public decimal TotalPrice => Items.Sum(item => item.Price * item.Quantity); public Cart(string sessionId, int? userId) { SessionId = sessionId; UserId = userId; } /// <summary> /// 添加商品到购物车 /// </summary> public void AddItem(int productId, int quantity, string variant = "") { // 需要从数据库获取商品详情以设置价格 decimal price = GetProductPrice(productId); var existingItem = Items.FirstOrDefault(i => i.ProductId == productId && i.Variant == variant); if (existingItem != null) { existingItem.Quantity += quantity; } else { Items.Add(new CartItem { ProductId = productId, Price = price, Quantity = quantity, Variant = variant }); } } private decimal GetProductPrice(int productId) { // 实际项目中应从数据库获取当前价格 string connString = WebConfigurationManager.ConnectionStrings["DB-NetShops"]?.ConnectionString; using (var conn = new SqlConnection(connString)) { string query = "SELECT Price FROM Products WHERE ProductID = @ProductID"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@ProductID", productId); conn.Open(); return Convert.ToDecimal(cmd.ExecuteScalar()); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值