2012-05-12 3 views
0

У меня возникла проблема с написанием метода в стиле шаблона шаблона. Но первый мой код:Создание уровня доступа к данным с использованием шаблона шаблона

Мой Базовый класс Я использую выглядит следующим образом:

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

Calling Код:

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 ш hich дает мне одну конкретную строку по id. Моя проблема заключается в том, как я могу вставить идентификатор в мой метод ExecuteReader без нарушения шаблона шаблона?

Надеюсь, вы можете мне помочь.

Thx

+0

Что вы имеете в виду подрыв шаблона patern? Вы можете переименовать параметр '@user_id' в '@id' и не переопределять метод GetParameters в любое время – gabba

+0

Возможно, вам потребуется другое имя поля id, но имя параметра может быть одинаковым для любых случаев – 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); 
... 

UPDATE # 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

Что делать, если я использую три разных параметры в инструкции SELECT ... WHERE в рамках метода ANY в будущем? Я хочу объявить параметры в классе UserDb, но мне нужно назначить значения для этих параметров. – MUG4N

+0

Возможно, вам потребуется другое имя поля id, но имя параметра может быть одинаковым для любых случаев – gabba

+0

Что делать, если я использую метод, который вызывает SELECT * FROM USERS WHERE USER_NAME = 'foo' AND AGE = 25 – MUG4N

Смежные вопросы