C# 在创建之前检查数据库是否存在
这看起来很琐碎,但现在让我很沮丧 我正在将C与SQLServer2005Express一起使用 我正在使用以下代码。我想在创建数据库之前检查它是否存在。但是,返回的整数是-1,这就是MSDN如何定义ExecuteOnQuery将返回的内容。现在,数据库确实存在,但它仍然返回-1。话虽如此,我如何才能使这项工作达到预期的效果C# 在创建之前检查数据库是否存在,c#,sql-server-2005,tsql,C#,Sql Server 2005,Tsql,这看起来很琐碎,但现在让我很沮丧 我正在将C与SQLServer2005Express一起使用 我正在使用以下代码。我想在创建数据库之前检查它是否存在。但是,返回的整数是-1,这就是MSDN如何定义ExecuteOnQuery将返回的内容。现在,数据库确实存在,但它仍然返回-1。话虽如此,我如何才能使这项工作达到预期的效果 private static void checkInventoryDatabaseExists(ref SqlConnection tmpConn, ref bool da
private static void checkInventoryDatabaseExists(ref SqlConnection tmpConn, ref bool databaseExists)
{
string sqlCreateDBQuery;
try
{
tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes");
sqlCreateDBQuery = "SELECT * FROM master.dbo.sysdatabases where name =
\'INVENTORY\'";
using (tmpConn)
{
tmpConn.Open();
tmpConn.ChangeDatabase("master");
using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn))
{
int exists = sqlCmd.ExecuteNonQuery();
if (exists <= 0)
databaseExists = false;
else
databaseExists = true;
}
}
}
catch (Exception ex) { }
}
这不应该吗
"SELECT * FROM master.dbo.sysdatabases where name = \'INVENTORY\'"
是这个吗
"SELECT * FROM master.dbo.sysdatabases where name = 'INVENTORY'"
同样根据MSDN
对于UPDATE、INSERT和DELETE语句,返回值是受命令影响的行数。当插入或更新的表上存在触发器时,返回值包括受插入或更新操作影响的行数以及受触发器影响的行数。对于所有其他类型的语句,返回值为-1。如果发生回滚,则返回值也是-1
您正在执行SELECT而不是DML语句。为什么不改用ExecuteReader方法呢?您不能使用,因为它将始终为SELECT返回-1,如MSDN链接所示
您必须使用处理结果集,例如选择DB_ID‘INVENTORY’作为数据库ID,或使用变量/参数:SELECT@DatabaseID=DB_ID‘INVENTORY’从SQL Server 2005开始,旧式的系统对象和系统数据库以及那些目录视图已被弃用。改为这样做-使用sys。模式视图,如sys.databases
这将适用于您作为参数传入的任何数据库名称,它将返回bool true=数据库存在,false=数据库不存在或发生错误。查询系统视图的另一种方法是使用函数db_id,如果存在,则返回数据库的id,否则为null。下面是T-SQL示例:
if (db_id('INVENTORY') is null)
begin
return 0
end
else
begin
return 1
end
读了几年后,有一种更清晰的表达方式:
public static bool CheckDatabaseExists(string connectionString, string databaseName)
{
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand($"SELECT db_id('{databaseName}')", connection))
{
connection.Open();
return (command.ExecuteScalar() != DBNull.Value);
}
}
}
为了搜索者的利益,如果您使用的是实体框架,则将:
using (var ctx = new MyDataModel())
{
dbExists = System.Data.Entity.Database.Exists(ctx.Database.Connection);
}
采用Stephen Lloyd的代码并添加了一些异步和sql注入缓解措施
public static async Task<bool> TestDatabase(string connectionString, string databaseName)
{
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("SELECT db_id(@databaseName)", connection))
{
command.Parameters.Add(new SqlParameter("databaseName", databaseName));
connection.Open();
return (await command.ExecuteScalarAsync() != DBNull.Value);
}
}
使用此程序集:Microsoft.SqlServer.SqlManagementObjects=>NuGet
我会改用ExecuteReader,因为你现在根本不做DML。。executescalar返回对象,因此您必须在分配前强制转换。它引发列名“INVENTORY”无效的异常抱歉,是的-数据库名称需要用单引号括起来-更新了我的答案这很有效。。如果不存在,则抛出未设置为对象实例的对象引用。否则它将返回一个非零的数据库id!只是想知道为什么不能在这里使用DB_ID?不容易出错,不是吗?看起来是其他人提交的-我很好奇您选择这种方式是否有原因,而不是在这里担心sql注入,使用参数化查询而不是字符串插值,但是db_id是sql Server T-sql函数,所以我看不出sql注入有任何问题。我发现这里使用的连接字符串不能指定要检查的数据库,这似乎是浪费时间。如果存在,则connection.Open将在不存在时引发异常。Open是否具有异步重载?
public static async Task<bool> TestDatabase(string connectionString, string databaseName)
{
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("SELECT db_id(@databaseName)", connection))
{
command.Parameters.Add(new SqlParameter("databaseName", databaseName));
connection.Open();
return (await command.ExecuteScalarAsync() != DBNull.Value);
}
}
using Microsoft.SqlServer.Management.Smo;
var dbExists = new Server(serverOrInstanceName).Databases.Contains(dataBaseName);