2012-05-12 51 views
0

我在模板模式样式中编写Method时遇到了一些问题。但首先我的代码:使用模板模式创建数据访问层

我的基类,我使用看起来像这样:

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)); 

正如你可以看到我已经实现了一个名为单W法这个ID给我一个特定的行。我的问题是我怎么可以将id推入我的ExecuteReader方法而不会破坏模板模式?

我希望你能帮助我。

THX

+0

您真正的意思是打破模板模板?您可以将参数'@user_id'重命名为'@id',并且不会随时重写GetParameters方法 – gabba

+0

您可能需要使用不同的id字段名称,但param的名称可以在任何情况下都是相同的 – gabba

回答

2

你为什么不使用对所有的实体,如@id同名的参数。那么你将不再需要GetParameters的东西。只需拨打

command.Parameters.AddWithValue("@id", id); 

UPDATE

如果你希望能够使用不同数量的参数,你可以使用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]); 
    } 
    ... 
} 
+0

如果我使用三种不同的参数在未来的ANY方法中的SELECT ... WHERE语句中?我想在UserDb类中声明参数,但必须为这些参数分配值。 – MUG4N

+0

您可能需要使用不同名称的id字段,但param的名称可以在任何情况下都是相同的 – gabba

+0

如果我使用的方法调用SELECT * FROM USERS WHERE USER_NAME ='foo'AND AGE = 25 – MUG4N