SqlDataReader执行查询报Invalid object name无效对象名异常
问题背景
服务逻辑为从公开API拉取文章数据,和数据库已有数据做去重校验后入库,报错在SqlDataReader初始化读取表数据时触发,相同的数据库查询代码在ASP.NET项目中运行无异常。
问题代码片段:
List<Thumbnail> Thumbnails = new List<Thumbnail>(); var client = new HttpClient { BaseAddress = new Uri("https://api.spaceflightnewsapi.net/v3/articles?_limit=100") }; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync(client.BaseAddress); if (response.IsSuccessStatusCode) { Thumbnails = JsonConvert.DeserializeObject<List<Thumbnail>>(response.Content.ReadAsStringAsync().Result); } if (Thumbnails != null) { for (int i = 0; i < Thumbnails.Count; i++) { Thumbnails[i].PublishedAt = Thumbnails[i].PublishedAt.ToUniversalTime(); } SqlConnection conn = new SqlConnection(connectionString); conn.Open(); SqlCommand cmdr = new SqlCommand("SELECT * FROM mobilesdb.dbo.thumbnails ORDER BY PublishedAt", conn) { CommandType = CommandType.Text }; SqlDataReader reader = await cmdr.ExecuteReaderAsync();//error: System.Data.SqlClient.SqlException: 'Invalid object name 'mobilesdb.dbo.thumbnails'.' try { while (reader.Read()) { Thumbnail thumbnail = new Thumbnail() { Title = reader.GetString(1), Url = reader.GetString(2), ImageUrl = reader.GetString(3), NewsSite = reader.GetString(4), Summary = reader.GetString(5), PublishedAt = reader.GetDateTime(reader.GetOrdinal(nameof(thumbnail.PublishedAt))), UpdatedAt = reader.GetDateTime(reader.GetOrdinal(nameof(thumbnail.UpdatedAt))), }; for (int i = 0; i < Thumbnails.Count; i++) { if (Thumbnails[i].Title.Equals(thumbnail.Title) && Thumbnails[i].NewsSite.Equals(thumbnail.NewsSite) && Thumbnails[i].Summary.Equals(thumbnail.Summary)) { Thumbnails.RemoveAt(i); } } } } catch (Exception) { } reader.Close();
报错附加信息:
Exception thrown: 'System.Data.SqlClient.SqlException' in mscorlib.dll An exception of type 'System.Data.SqlClient.SqlException' occurred in mscorlib.dll but was not handled in user code Invalid object name 'thumbnails'.
根因分析
不要因为同一段SQL在其他项目能跑就排除连接/对象存在性问题,90%的这类报错都是以下原因导致:
- 核心问题:当前服务的数据库连接指向的实例/库中,不存在
mobilesdb.dbo.thumbnails这张表- 核对当前项目的
connectionString配置和正常运行的ASP.NET项目是否完全一致,常见坑点:不同项目用了独立的LocalDB实例、配置文件变换(Debug/Release)切到了测试库、连接地址/实例名写错连到了其他SQL Server实例,这些场景下目标实例里根本没有建过这张表 - 检查连接账号权限:如果账号对
mobilesdb库没有访问权限,SQL Server不会明确返回权限不足,而是直接抛出"无效对象名"的错误 - 检查对象名拼写:确认库名、schema名、表名的拼写和实际一致,注意SQL Server默认实例排序规则不区分大小写,但部分自定义实例会开启大小写敏感,拼写偏差会直接报表不存在
- 核对当前项目的
- 代码附带的隐患(和当前报错无关但会引发其他线上问题):
- 遍历
Thumbnails列表时直接调用RemoveAt(i)删除元素,会导致集合索引错位,漏判重复项甚至触发索引越界 SqlConnection/SqlCommand/SqlDataReader没有用using包裹,存在数据库连接泄露风险- 空catch块直接吞掉所有异常,出现问题时无法定位根因
- 异步方法调用
.Result取结果,在ASP.NET这类带同步上下文的环境下极易触发死锁 ExecuteReaderAsync放在try块外面,抛出的数据库异常完全不会被捕获
- 遍历
修复方案
- 先验证连接正确性:临时加测试语句执行
SELECT DB_NAME(), @@SERVERNAME,确认当前连接的实例名、数据库名和预期一致,再执行SELECT * FROM mobilesdb.sys.tables WHERE name = 'thumbnails'确认表存在 - 对齐两个项目的数据库连接字符串,确认账号权限满足库表访问要求
- 修正代码逻辑问题,参考实现:
List<Thumbnail> Thumbnails = new List<Thumbnail>(); var client = new HttpClient { BaseAddress = new Uri("https://api.spaceflightnewsapi.net/v3/articles?_limit=100") }; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync(client.BaseAddress); if (response.IsSuccessStatusCode) { // 替换.Result为await避免死锁 string respContent = await response.Content.ReadAsStringAsync(); Thumbnails = JsonConvert.DeserializeObject<List<Thumbnail>>(respContent); } if (Thumbnails != null) { // 统一转UTC时间 for (int i = 0; i < Thumbnails.Count; i++) { Thumbnails[i].PublishedAt = Thumbnails[i].PublishedAt.ToUniversalTime(); } // using包裹数据库对象,自动释放资源 await using SqlConnection conn = new SqlConnection(connectionString); await conn.OpenAsync(); SqlCommand cmdr = new SqlCommand("SELECT * FROM mobilesdb.dbo.thumbnails ORDER BY PublishedAt", conn) { CommandType = CommandType.Text }; await using SqlDataReader reader = await cmdr.ExecuteReaderAsync(); // 先把已有数据的唯一标识存入HashSet,避免边遍历边删列表导致的索引错位 HashSet<(string title, string newsSite, string summary)> existedRecords = new(); while (await reader.ReadAsync()) { Thumbnail thumbnail = new Thumbnail() { Title = reader.GetString(1), Url = reader.GetString(2), ImageUrl = reader.GetString(3), NewsSite = reader.GetString(4), Summary = reader.GetString(5), PublishedAt = reader.GetDateTime(reader.GetOrdinal(nameof(Thumbnail.PublishedAt))), UpdatedAt = reader.GetDateTime(reader.GetOrdinal(nameof(Thumbnail.UpdatedAt))), }; existedRecords.Add((thumbnail.Title, thumbnail.NewsSite, thumbnail.Summary)); } // 批量移除重复项 Thumbnails.RemoveAll(t => existedRecords.Contains((t.Title, t.NewsSite, t.Summary))); // 后续入库逻辑... }
- 删除空catch块,所有异常必须记录日志,禁止直接吞错。
内容的提问来源于stack exchange,提问作者needlide
相关产品推荐
相关产品推荐

