如何将计算列添加到EF4模型中?

uhl*_*eka 7 sql-server entity-framework calculated-columns entity-framework-4

给定MS SQL 2008中的"用户"表和"登录"表:

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,
)
Run Code Online (Sandbox Code Playgroud)

如何调整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]
Run Code Online (Sandbox Code Playgroud)

但有没有办法可以修改User_User模型以包含计算的列?

编辑:我正在寻找一种方法来获取用户或列表<用户>包括单个数据库查询中的最大(Util.LastLogin)日期.

Mor*_*avi 5

非常好的问题,是的,在EF4中有一种完美的方法:

自定义属性是一种为实体提供计算属性的方法.好消息是,自定义属性不一定需要从同一个实体上的其他现有属性计算,通过我们即将看到的代码,它们可以从我们喜欢的任何东西计算出来!

以下是步骤:
首先创建一个分部类并在其上定义一个自定义属性(为简单起见,我假设User_User表已映射到User类,Util_Login已映射到Util)

public partial class User {
    public DateTime LastLoginDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

所以,正如你在这里看到的,不是在模型中创建LastLoginDate属性,而是需要映射回数据存储,我们在partial类中创建了属性,然后我们可以选择在对象期间填充它如果您不相信每个实体对象都需要提供该信息,则实现按需提供.

在您的情况下,预先计算每个正在实现的用户LastLoginDate自定义属性是有用的,因为我认为将为所有(或至少大多数)实体实现此值.否则,您应该考虑仅在需要时而不是在对象实现期间计算属性.

为此,我们将利用ObjectContext.ObjectMaterialized Event,该事件是从查询返回数据时引发的,因为ObjectContext正在从该数据创建实体对象.ObjectMaterialized事件是实体框架4的事情.所以我们需要做的就是创建一个事件处理程序并将其订阅到ObjectMaterialized Event.

放置此代码(订阅事件)的最佳位置是OnContextCreated方法.此方法由上下文对象的构造函数和构造函数重载调用,这是一个没有实现的部分方法,只是由EF代码生成器创建的方法签名.

好的,现在您需要为ObjectContext创建一个分部类.(我假设名字是UsersAndLoginsEntities)并将事件处理程序(我将其命名为Context_ObjectMaterialized)订阅到ObjectMaterialized Event.

public partial class UsersAndLoginsEntities {
    partial void OnContextCreated() {
        this.ObjectMaterialized += Context_ObjectMaterialized;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一步(实际工作)将实现此处理程序以实际填充我们的自定义属性,在这种情况下非常容易:

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

Run Code Online (Sandbox Code Playgroud)


希望这可以帮助.