0

最近まで App_Code フォルダーにすべてのコードが含まれていた ASP.NET Web サイト プロジェクトがあります。ORM として Entity Framework 4 を使用します。アプリケーションは 3 つの「セクション」に分かれています (各顧客に 1 つとしましょう)。各セクションには独自のデータベースがあります (ただしスキーマは同じです)。これはパフォーマンス上の理由によるもので、データベースはそれぞれ 10GB を超え、数百万行あります。

オブジェクトが作成されるたびに、contextセクション ID を保持するセッション変数が呼び出され、このコンテキストに対して独自の接続文字列が選択されます。

次のようになります (以下は静的Connectionクラスのメンバーです)。

public static MyEntities GetEntityContext()
{
    if (HttpContext.Current.Session["section"] == null)
    {
        HttpContext.Current.Response.Redirect("~/Login.aspx");
    }
    var context = new MyEntities(GetEntityConnectionStringForSection((int)HttpContext.Current.Session["section"]);
    return context;
}

private static string GetEntityConnectionStringForSection(int section)
{
    switch (section)
    {
        case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
        case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
        case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
        default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
    }
}

それは非常にうまく機能し、データアクセスが実行されるたびにセッションがタイムアウトした場合の状況も処理します.

最近、2 つの Web サイト間で DB クラスを共有する必要があったため、すべての DB クラスを別のクラス ライブラリと参照System.Webライブラリに移動しましたが、これは悪い習慣ですが、機能しています。

次のステップは、ユニットとモジュールのテストを含めることです。これは、私が読んだHttpContextように、ライブラリで使用する場合は非常に困難または不可能であるため、参照を取り除きたいと考えていSystem.Webます。この状況のベストプラクティスは何ですか?

エンティティクラス内からも呼び出されるHttpContextため、単に渡すことはできないと思います。GetEntityContext()これはおそらくリファクタリングできますが。だから多分これは私が行くべき場所ですか?

また、現在のセクション ID をこのライブラリ全体に渡すことができるかどうかも疑問に思いましたか? 私が理解している限り、アプリケーションを使用するすべてのユーザーに共通であるため、単なる静的プロパティにすることはできません。これはユーザー固有である必要があります。

透過的な接続文字列の選択とセッション タイムアウトの処理を失うことなく、自動テストを可能にすることが目的であると再確認します。

この段階で何か根本的に間違ったことをした場合もお知らせください。この質問は明日の朝 (UTC の午前 8 時) にもう一度見ることができるので、それまで私の沈黙に落胆しないでください。

編集:

Connectionライブラリでのクラスの使用例:

public partial class Store
{
    public static List<Store> GetSpecialStores()
    {
        using (var context = Connection.GetEntityContext())
        {
          return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
        }
    }
}
4

1 に答える 1

1

ライブラリ内でインターフェイスを宣言しIContextProvider、それを使用してコンテキストを取得できます。何かのようなもの:

public interface IContextProvider
{
   MyEntities GetEntityContext();
}

これにより、ライブラリがテスト可能になります。IContextProviderWeb プロジェクトでは、実装をライブラリに挿入できます。

public class WebContextProvider : IContextProvider
{
    public MyEntities GetEntityContext()
    {
        if (HttpContext.Current.Session["section"] == null)        
            HttpContext.Current.Response.Redirect("~/Login.aspx");

        int sectionId = (int)HttpContext.Current.Session["section"];
        string connectionString = GetEntityConnectionStringForSection(sectionId);
        var context = new MyEntities(connectionString);
        return context;
    }

   private static string GetEntityConnectionStringForSection(int section)
   {
       switch (section)
       {
          case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
          case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
          case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
          default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
       }
   }
}

このインターフェイスをリポジトリまたは他のデータ アクセス クラスに挿入します。

public partial class Store
{
    private IContextProvider contextProvider;

    public Store(IContextProvider contextProvider)
    {
        this.contextProvider = contextProvider;
    }

    public List<Store> GetSpecialStores()
    {
        using (var context = contextProvider.GetEntityContext())
        {
          return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
        }
    }
}
于 2012-07-19T14:59:41.960 に答える