2013-02-18 3 views
4

Я пытаюсь создать один объект, который будет отвечать за чтение всех параметров доступа пользователей.Убедитесь, что Singleton вызывает запрос db только один раз

Я создал класс, как так:

public class SettingsManager 
{ 
    private static string _connString = 
     @"Data Source=MyDB;Initial Catalog=IT;Integrated Security=True;Asynchronous Processing=true;"; 
    private const string _spName = "SettingTest"; 
    private IEnumerable<string> _mySettings; 
    private static readonly Lazy<SettingsManager> _instance = new Lazy<SettingsManager>(() => new SettingsManager()); 

    private SettingsManager() 
    { 
     //Console.WriteLine("Hello from constructor"); 
     if (_mySettings == null) 
      _mySettings = ReadSettings(); 
    } 

    public static SettingsManager Instance 
    { 
     get { return _instance.Value; } 
    } 

    public bool CanDo(string setting) 
    { 
     return _mySettings.Contains(setting); 
    } 

    private IEnumerable<string> ReadSettings() 
    { 
     try 
     { 
      using (var conn = new SqlConnection(_connString)) 
      { 
       using (var cmd = new SqlCommand()) 
       { 
        cmd.Connection = conn; 
        cmd.CommandText = _spName; 
        cmd.CommandType = CommandType.StoredProcedure; 
        conn.Open(); 
        using (var reader = cmd.ExecuteReader()) 
        { 
         return reader.Select(SettingParser).ToList(); 
        } 
       } 
      } 
     } 
     catch 
     { 
     } 
     return null; 
    } 

    private string SettingParser(SqlDataReader r) 
    { 
     try 
     { 
      return r[0] is DBNull ? null : r[0].ToString(); 
     } 
     catch 
     { 
     } 
     return null; 
    } 
} 

И SqlDataReader Extension

public static class DBExtensions 
{ 
    public static IEnumerable<T> Select<T>(
     this SqlDataReader reader, Func<SqlDataReader, T> projection) 
    { 
     while (reader.Read()) 
     { 
      yield return projection(reader); 
     } 
    } 
} 

Тогда внутри моего приложения, я могу назвать это как так:

SettingsManager.Instance.CanDo("canWrite") 

это возвращает значение true/false, зависит от уровня доступа пользователя.

Мои вопросы:

  1. Это поточно? Есть ли шансы, что БД будет запросить несколько раз? Как предотвратить это?

  2. Должен ли я использовать ожидание и асинхронный режим? Я запрашиваю db только один раз. Как я могу улучшить это? (Await и асинхронной действительно являются новыми для меня, потому что я только что переехал из .NET3.5 до 4,5)

+0

http://csharpindepth.com/Articles/General/Singleton.aspx –

+0

@Ravi - Я использую один из этой модели - Lazy <> – Misiu

+0

@Ravi - http://geekswithblogs.net/BlackRabbitCoder/archive/ 2010/05/19/c-system.lazylttgt-and-the-singleton-design-pattern.aspx LazySingleton3 – Misiu

ответ

2

1) Является ли эта нить безопасной?

Да.

Есть ли шансы, что БД будет запросить несколько раз?

No.

2) Должен ли я использовать ждать и асинхронной?

Это зависит от того, нужен ли вам асинхронный доступ к вашей базе данных. Если вам нужно, вы можете использовать асинхронный ADO.NET API.

+0

простой, быстрый и приятный ответ :) Просто хотел убедиться, что мой код в порядке :) – Misiu

+0

Да, ваш код в безопасности. 'Lazy ' - это поточно-безопасный класс, поэтому ваш синглтон-шаблон правильно реализован. Кроме того, вы правильно распоряжаетесь всеми ресурсами IDisposable, обертывая их с помощью замечательных приложений. –

1

1) да это, Потокобезопасная

поточно-Singleton: Эта реализация использует внутренний класс, чтобы сделать экземпляр .NET полностью ленивым. Только GetInstance() запускает инициализатор типа; поэтому эта версия столь же ленива, как и классическая версия. И он будет работать так же круто, как и любая другая версия.

public sealed class Singleton 
{ 

    private Singleton() {} 

    public static Singleton GetInstance() 
    { 
     return NestedSingleton.singleton; 
    } 

    class NestedSingleton 
    { 
     internal static readonly Singleton singleton = new Singleton(); 

     static NestedSingleton() {} 
    } 
} 

2) Это зависит, если вы хотите асинхронный доступ к БД.

+0

Вы не можете использовать ключевое слово 'this' внутри статического члена. –

+0

1. Анти-шаблон, использующий это для блокировки, 2. Lazy <> на самом деле является потокобезопасным –

+0

@CuongLe - да, Lazy <> является потокобезопасным - мне просто нужно убедиться, что я позвоню своему запросу только один раз. Мой код должен быть хорошим, но, возможно, есть способы его улучшить :) – Misiu

1
  1. Является ли эта нить безопасной?

Да. Вы правильно используете тип Lazy<T>, чтобы обеспечить безопасность потока.

  1. Должен ли я использовать ожидание и асинхронное использование?

Я бы порекомендовал его. Прямо сейчас, в первый раз, когда ваш код приложения вызывает SettingsManager.Instance.CanDo("canWrite"), он будет блокироваться до тех пор, пока БД не ответит. Также возможно иметь реализацию async, где ваши потребители могут делать (await SettingsManager.Instance).CanDo("canWrite") (или await SettingsManager.CanDoAsync("canWrite")). Это означает, что ваши потребители не блокируются во время ожидания БД.

Вы можете использовать async -Ready версию Lazy<T> под названием AsyncLazy<T>, originally developed by Stephen Toub и included in my AsyncEx library.

+0

спасибо за этот ответ, я думаю, что я пытаюсь сделать вторую версию CanDo с async :) – Misiu

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