web-dev-qa-db-ja.com

アプリケーションのドロップダウンリストの維持

SOLID原則とパフォーマンスを考慮して)アプリケーション全体(市、州など)のドロップダウンリストを維持するための最良の方法は何ですか?

現在、リストの値を静的プロパティにロードし、同じように使用しています

public int DestCountry { get; set; }

private string _CountryText;
public string CountryText
{
    get
    {
        if (this.DestCountry > 0)
        {
            _CountryText = Lists.CountryList.Find(x => x.Value == Convert.ToString(this.DestCountry)).Text;
        }
        return _CountryText;
    }
}

しかし、これが可能な最善のアプローチかどうかはわかりません。提案していただけませんか。

4
gvk

これはいくつかの異なる要因に依存します:

  • まず、それらを維持する責任があるのは誰ですか(アプリケーションの開発者、ユーザー、一部のパワーユーザー、管理者)?
  • リストはアプリケーションの1つのバージョンに固定されていますか、それとも新しいバージョンを配信せずにそれらの値を変更する必要がありますか?
  • それらは1つの言語で本当に修正されたテキストですか、それともローカライズされると思いますか?
  • 値のリストは1つのフォーム/ダイアログ/クラスでのみ必要ですか、それともアプリケーションの別の場所で必要ですか?
  • 異なる場所で必要な場合、常にまったく同じ方法で必要ですか、それとも変更された方法で必要になることがありますか?たとえば、コンテキストに応じて、拡張する必要がありますか?
  • 選択したドロップダウン値をどこかに(たとえば、データベースに)保存する必要がある場合、どのように保存しますか?固定テキストとして?インデックスとして?インデックスからテキストへのマッピングはどこで行われますか?

これらの質問への答えがわかっている場合は、特定のケースに最適な場所を自分で解決できると思います。これは、フォーム内のハードコードされたリスト、再利用可能なクラスまたは拡張可能なクラスのリストのいずれかであり、リソースファイル、構成ファイル、またはデータベースに格納されている可能性があります。同じ情報を2つの異なる場所に保存しないでください。

2
Doc Brown

まず、アプリに必要なすべてのデータを提供するデータアクセスインターフェイスから始めます。許可されている郡を提供するための問題のメソッドのみを含む単純なバージョンを次に示します。

public interface IDataAccessProvider
{
    Country[] GetCountries();
}

public class Country 
{
    public string Id { get; set; }
    public string Name { get; set; }
}

そして、これがそのインターフェースの最初の実装です:

public class DataAccessProvider : IDataAccessProvider
{
   // gets them from dbase, file, xml, blah blah blah
   // doesn't matter, just some resource that isn't hard coded
   return new List<County>() { ... };
}

これが、アプリケーションキャッシュに物を出し入れするための静的ヘルパークラスです。アプリケーションキャッシュは、静的データなどに頼ることなく、データをアプリに保存してネットワーク/データベース/ fileIOなどに保存する優れた方法です。

public static class CacheHelper
{
    public static void Insert<T>(string cacheKey, T objToCache, double hoursBeforeExpiration)
    {
        if (objToCache != null && typeof(T).IsValueType && Nullable.GetUnderlyingType(typeof(T)) == null)
            throw new Exception(string.Format("Dont add non-nullable stuff to the cache. Type: {0} KeyName: {1}", typeof(T), cacheKey));

        var expire = DateTime.Now.AddHours(hoursBeforeExpiration);
        HttpContext.Current.Cache.Insert(cacheKey, objToCache, null, expire, Cache.NoSlidingExpiration);
    }

    public static T Get<T>(string cacheItemName)
    {
        try { return (T)HttpContext.Current.Cache[cacheItemName]; }
        catch { return default(T); }
    }

    public static T RetrieveThroughCache<T>(string keyName, Func<T> retrievalCall, double hoursBeforeExpiration = 1)
    {
        var objFromCache = CacheHelper.Get<T>(keyName);
        if (objFromCache != null)
            return objFromCache;

        var objFromDataCall = retrievalCall();
        Insert(keyName, objFromDataCall, hoursBeforeExpiration);
        return objFromDataCall;
    }

    public static void Remove(string keyName)
    {
        HttpContext.Current.Cache.Remove(keyName);
    }
}

次に、そのDataAccessProviderクラスから、上記のキャッシュメソッドの使用方法を知っている新しいクラスを継承します。

public class CachedDataAccessProvider : DataAccessProvider 
{
    public override Country[] GetCountries() 
    {
        return CacheHelper.RetrieveThroughCache("AppCountries", () => base.GetCountries());
    }
}

これで、MVC ViewModelで、データプロバイダーインターフェイスのインスタンスをどこか下(ベースViewModelコンストラクター、コントローラーからのDIなど)から取得し、データプロバイダーのGetCountries()メソッドを呼び出すことができます。最初の呼び出しはデータベースから新しいものを取得し、その後の1日中のヒット(静的クラスのデフォルトはキャッシュ内の24時間です)は、キャッシュから直接取得します。 County[]値をSelectListItemsに入力して、ドロップダウンを強化します。

public class MyWhateverViewModel
{
    public string SelectedCountryId { get; set; }

    public IEnumerable<SelectListItem> GetCountryChoices() 
    {
        var dataProvider = GetIDataProviderInstance(); // or pass as param in constructor, etc
        return from country in dataProvider.GetCountries()
               select new SelectListItem {
                Text = country.Name,
                Value = country.Id,
                Selected = country.Id == SelectedCountryId 
               };
    }
}
2
Graham