考虑以下类
public class DataManager
{
private SqlConnection cn;
public SqlCommand cmd;
public DataManager(bool initializeCmd=true)
{
string conString="server=192.168.1.20;User Id=sa;pwd=123;Persist Security Info=True; database=testDB";
cn = new SqlConnection(conString);
if (initializeCmd)
cmd = new SqlCommand();
}
public void OpenDbConnection()
{
if (cn.State == ConnectionState.Closed)
cn.Open();
}
public void CloseDbConnection()
{
if (cn.State == ConnectionState.Open)
cn.Close();
}
public bool Update_Database()
{
cmd.Connection = cn;
OpenDbConnection();
int n=cmd.ExecuteNonQuery();
CloseDbConnection();
if(n>0) { return true; }
else { return false; }
}
public bool Update_Database(string cmdTxt, bool isProcedure)
{
cmd = new SqlCommand(cmdTxt, cn);
if (isProcedure)
cmd.CommandType = CommandType.StoredProcedure;
else
cmd.CommandType = CommandType.Text;
OpenDbConnection();
int n=cmd.ExecuteNonQuery();
CloseDbConnection();
if(n>0) { return true; }
else { return false; }
}
}
现在考虑第二类
public class staff
{
DataManager dm;
public bool resetPwd(string code)
{
dm = new DataManager(false);
string query= "UPDATE Staff WHERE pwd='123' WHERE code="+code;
return dm.Update_Database(query,false);
}
public bool changePwd(string code,string pwd)
{
dm = new DataManager();
dm.cmd.CommandText = "UPDATE Staff WHERE pwd=@pwd WHERE code=@code";
dm.cmd.Parameters.Clear();
dm.cmd.Parameters.AddWithValue("@code", code);
dm.cmd.Parameters.AddWithValue("@code", code);
return dm.Update_Database();
}
}
DataManager类是处理数据库操作的常用类。现在我的问题是是否有办法阻止我使用
Update_Database()
调用
时的函数
dm = new DataManager(false)
代替
dm = new DataManager()
from staff class。因为如果我使用dm = new DataManager(false),它将抛出一个错误,因为sql命令对象没有初始化。
没有什么可以阻止别人初始化dm = new DataManager(true)
。如果需要的数据库更新不可用,则将其从DataManager
移出。创建另一个DatabaseUpdater
类,负责数据库更新操作。注意:Update
方法的名称是误导-他们应该执行UPDATE查询,但我可以传递DELETE查询文本,并执行它。
顺便说一句,DataManager
的有用性是有争议的。ADO。NET使用连接池来最小化打开连接的成本。另外,硬编码连接字符串也不是一个好主意。使用配置文件的connectionStrings部分来提供它们。
我建议你看一下Dapper库,它会使你的代码看起来像这样:
public bool ChangePassword(string code, string pwd)
{
using(DbConnection conn = GetConnection())
{
string sql = "UPDATE Staff SET pwd=@pwd WHERE code=@code";
int updatedRowsCount = conn.Query<int>(sql, new { code, pwd }).First();
return updatedRowsCount == 1;
}
}
连接将自动打开和关闭。命令将被创建,所有参数将被添加到命令中。我还没有提供GetConnection
实现-它负责读取连接字符串并返回新连接。
最后一个建议-避免接受布尔参数的方法。这种参数很容易混淆。DataManager(true)
是什么意思?与DataManager(false)
有何不同?
不能自动显示和隐藏功能。一旦你的代码编译好了,就不能动态修改了。
你能做的不是那么"整洁"的是抛出一个异常或者根本不运行代码。这是非常糟糕的界面设计,因为它创建的行为不容易理解。
如果你真的想,你可以设置你的DataManager接收数据库连接字符串:
string connectionString = "...";
DataManager dm = new DataManager(connectionString);
如果实现者不知道连接字符串,他们将无法打开连接。
这不是"最佳设计",但它回答了你的问题。
一个更好的解决方案可能只是暴露一个bool属性,如果命令是可用的。这样,如果允许使用该方法,消费者可以先进行测试。如果他们仍然想调用它,那么抛出一个异常。
重要的是他们有办法自己测试。
。NET 4.5可能是4,引入了可以在运行时改变方法的动态类对象。我不想在我的代码中这样使用它,但它确实存在。
为什么不在执行Update_Database()
之前检查initializeCmd == true
(从函数内部)?如果它的值是false
(只是返回),则执行NOP。您可以将SqlCommand
初始化为默认值,这样调用该方法就不会产生任何副作用。或者在执行之前检查命令是否为空。您还可以对不同的专门化类行为使用继承。
编辑:如果你不喜欢#warning
, . net的代码契约库可以帮助你根据类的使用方式显示警告。
代码契约是任何。net程序中用于指定代码行为的静态库方法。
使用库使您能够使用静态检查来检查契约违反。(如果你真的认为这是必要的!)