我在模板模式样式中编写Method有一些问题。但首先是我的代码:
我使用的My Base类看起来像这样:
public abstract class DbBase<T> where T : new()
{
protected abstract Value CommandValue { get; }
protected abstract CommandType CommandType { get; }
protected abstract Mapper<T> GetMapper();
protected abstract IDbConnection GetConnection();
protected abstract Collection<IDataParameter> GetParameters(IDbCommand command);
public Collection<IDataParameter> Paramaters { get; set; }
#region Public Methods
public T Single(int id)
{
return ExecuteReader(id).SingleOrDefault();
}
public Collection<T> All()
{
return ExecuteReader();
}
#endregion
#region Private Methods
private Collection<T> ExecuteReader(int? id = null)
{
var collection = new Collection<T>();
using (var connection = GetConnection())
{
var command = connection.CreateCommand();
command.Connection = connection;
command.CommandType = CommandType;
if (id.HasValue && id.Value > 0)
command.CommandText = CommandValue.Single;
else
command.CommandText = CommandValue.All;
var parameters = GetParameters(command);
if (parameters != null)
{
foreach (var param in GetParameters(command))
command.Parameters.Add(param);
}
try
{
connection.Open();
using (var reader = command.ExecuteReader())
{
try
{
var mapper = GetMapper();
collection = mapper.MapAll(reader);
return collection;
}
finally
{
if (!reader.IsClosed)
reader.Close();
}
}
}
catch (Exception ex)
{
throw new DbBaseException(ex.Message, ex);
}
finally
{
if (connection.State != ConnectionState.Closed)
connection.Close();
}
}
}
#endregion
}
现在,对于可能会被更改的每一段代码,我都有一个继承的详细信息类:
public class UserDb : DbBase<User>
{
private static readonly string ALL = "SELECT * FROM [USER]"; //don't use star!
private static readonly string SINGLE = "SELECT * FROM [USER] WHERE USER_ID = @USER_ID";
private static readonly CommandType commandType = CommandType.Text;
protected override Value CommandValue
{
get
{
var value = new Value
{
Single = SINGLE,
All = ALL
};
return value;
}
}
protected override CommandType CommandType
{
get { return commandType; }
}
protected override Mapper<User> GetMapper()
{
return new UserMapper();
}
protected override Collection<IDataParameter> GetParameters(IDbCommand command)
{
var parameters = new Collection<IDataParameter>();
var param = command.CreateParameter();
param.ParameterName = "@USER_ID";
param.Value = 2;
parameters.Add(param);
return parameters;
}
}
致电代码:
var userDb = new UserDb();
var user = userDb.Single(1);
if (user != null)
Console.WriteLine(string.Format("{0}, {1}, {2}", user.UserId, user.Username, user.Password));
正如您所看到的,我已经实现了一个名为Single的方法,它通过id为我提供了一个特定的行。我的问题是如何在不破坏模板模式的情况下将id推入我的ExecuteReader方法?
我希望你能帮助我。
THX
答案 0 :(得分:2)
为什么不使用与@id
等所有实体具有相同名称的参数。那么你将不再需要GetParameters
的东西了。只需致电
command.Parameters.AddWithValue("@id", id);
<强>更新强>
如果您希望能够使用不同数量的参数,可以使用params
关键字,这样您就可以传递不同数量的参数(包括零)。
public T Single(params int[] id)
{
return ExecuteReader(id).SingleOrDefault();
}
和
private Collection<T> ExecuteReader(params int[] id)
{
...
for (int i = 0; i < id.Length; i++) {
command.Parameters.AddWithValue("@id" + i, id[i]);
}
...
}
您必须为参数命名@id0, @id1, @id2, ...
var coll = ExecuteReader();
var coll = ExecuteReader(2);
var coll = ExecuteReader(5, 77);
...
var result = db.Single(1);
var result = db.Single(4, 13);
var result = db.Single(5, 100, 1);
...
更新#2
您还可以从SQL文本中提取参数名称
private Collection<T> ExecuteReader(params object[] p)
{
...
var matches = Regex.Matches(sql, @"@\w+");
if (matches.Count != p.Length) {
throw new ArgumentException("The # of parameters does not match ...");
}
for (int i = 0; i < p.Length; i++) {
command.Parameters.AddWithValue(matches[i].Value, p[i]);
}
...
}