7

MS SQL 2008 に「User」テーブルと「Login」テーブルがあるとします。

CREATE TABLE [dbo].[User_User](
    [UserID] [int] IDENTITY(1000,1) NOT NULL,
    [UserName] [varchar](63) NOT NULL,
    [UserPassword] [varchar](63) NOT NULL
)
CREATE TABLE [dbo].[Util_Login](
    [LoginID] [int] IDENTITY(1000,1) NOT NULL,
    [User_UserID] [int] NOT NULL, -- FK REFERENCES [dbo].[User_User] ([UserID])
    [LoginDate] [datetime] NOT NULL,
)

User_Userエンティティ フレームワーク モデル オブジェクトを調整して、MAX(LoginDate) を返す「UserLastLogin」列を含めるにはどうすればよいですか?

SQL ビューを中心に EF4 モデルを作成できることはわかっています。

CREATE VIEW [v_User_User]
AS
SELECT 
        [User_User].*, 
        (
                SELECT MAX(LoginDate) 
                FROM [Util_Login] 
                WHERE User_UserID = UserID
        ) AS UserLastLogin
FROM [User_User]

しかし、User_User モデルを変更して計算列を含める方法はありますか?

編集: 単一の db クエリで Max(Util.LastLogin) 日付を含む User または List<User> をフェッチする方法を探しています。

4

3 に答える 3

5

非常に良い質問です。はい、EF4 でこれを実現する完璧な方法があり ます。

カスタム プロパティは、計算されたプロパティをエンティティに提供する方法です。幸いなことに、カスタム プロパティは、まったく同じエンティティの他の既存のプロパティから必ずしも計算する必要はありません。これから説明するコードによって、好きなものから計算することができます!

手順は次のとおりです。
まず、部分クラスを作成し、カスタム プロパティを定義します (簡単にするために、User_Userテーブルが User クラスにマップされ、Util_Loginが Util にマップされていると仮定します) 。

public partial class User {
    public DateTime LastLoginDate { get; set; }
}

したがって、ここでわかるように、モデルに LastLoginDate プロパティを作成するのではなく (データ ストアにマップし直す必要があります)、部分クラスにプロパティを作成し、オブジェクトの実行中にそれを設定するオプションがあります。すべてのエンティティ オブジェクトがその情報を提供する必要がないと思われる場合は、 マテリアライゼーションまたはオンデマンド。

あなたの場合、実体化されるすべてのUserのLastLoginDateカスタム プロパティを事前に計算すると便利です。それ以外の場合は、オブジェクトの実体化中ではなく、必要に応じてプロパティの計算を検討する必要があります。

そのために、ObjectContext がそのデータからエンティティ オブジェクトを作成しているため、クエリからデータが返されるたびに発生するObjectContext.ObjectMaterialized Eventを活用します。ObjectMaterialized イベントは Entity Framework 4 のものです。したがって、必要なことは、イベント ハンドラーを作成し、それを ObjectMaterialized イベントにサブスクライブすることだけです。

このコード (イベントをサブスクライブする) を配置するのに最適な場所は、OnContextCreated Method内です。このメソッドは、コンテキスト オブジェクトのコンストラクターとコンストラクターのオーバーロードによって呼び出されます。これは、EF コード ジェネレーターによって作成された単なるメソッド シグネチャであり、実装されていない部分的なメソッドです。

では、ObjectContext の部分クラスを作成する必要があります。(名前だと思います。UsersAndLoginsEntities ) を作成し、イベント ハンドラー (私はContext_ObjectMaterializedと名付けました) をObjectMaterialized Eventにサブスクライブします。

public partial class UsersAndLoginsEntities {
    partial void OnContextCreated() {
        this.ObjectMaterialized += Context_ObjectMaterialized;
    }
}

最後のステップ (実際の作業) は、このハンドラーを実装してカスタム プロパティを実際に入力することです。この場合は非常に簡単です。

void Context_ObjectMaterialized(object sender, ObjectMaterializedEventArgs args) 
{
    if (args.Entity is User) {        
        User user = (User)args.Entity;
        user.LastLoginDate = this.Utils
                .Where(u => u.UserID == user.UserID)
                .Max(u => u.LoginDate);
    }
}


お役に立てれば。

于 2010-09-21T02:09:55.487 に答える
1

コレクションをロードせずに、関連する 2 つのエンティティのカウント プロパティが必要な状況がありました。私が見つけた 1 つのことは、他のエンティティ コレクションを照会するときに ObjectMaterialized イベント ハンドラーで例外がスローされないように、接続文字列に MultipleActiveResultSets=True を含める必要があることです。

于 2012-05-23T08:15:31.003 に答える
1

熟考の末、次の解決策にたどり着きました。

まず、すべての User フィールドと LastLogin 日付フィールドを含むビューを作成します (元の投稿から)。

ユーザー ( User_Modelと呼びます) とユーザー ビュー ( UserView_Modelと呼びます) を EF モデルに追加した後、User_Model の周りにラッパー クラス ( User_Wrapperと呼びます) を作成し、LastLogin の DateTime プロパティを追加しました。

User_Wrapper クラスを変更して、UserView_Model からフェッチし、User_Model と UserView_Model の間で共有されるすべてのプロパティを反映して、基礎となる User_Model にデータを入力します。最後に、取得した User_View に基づいて User_Wrapper.LastLogin プロパティを設定します。

他のすべての機能 (作成、更新、削除...) は、User_Model で動作します。Fetch のみが UserView_Model を使用します。


これは何をしたのですか?単一の User_Wrapper または List<User_Wrapper> を設定するためのデータベース呼び出しが 1 つだけになりました。

欠点は?私の UserView_Model には関連付けられたリレーションシップがないため、EF ObjectContext を使用して熱心な読み込みを行うことはできないと思います。幸いなことに、私の状況では、それが問題になることはありません。

より良い方法はありますか?

于 2010-09-23T20:01:19.210 に答える