在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,
)
如何调整 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模型以包含计算出的列?
编辑:我正在寻找一种获取用户或列表的方法<用户>包括单个数据库查询中的Max(Util.LastLogin)日期。
答案 0 :(得分:5)
非常好的问题,是的,在EF4中有一个完美的方法:
自定义属性 是一种向实体提供计算属性的方法。好消息是,自定义属性不一定需要从同一个实体上的其他现有属性计算,通过我们即将看到的代码,它们可以从我们喜欢的任何东西计算出来!
以下是步骤:
首先创建一个分部类并在其上定义一个自定义属性(为简单起见,我假设 User_User 表已映射到User类,而 Util_Login 已映射到Util)
public partial class User {
public DateTime LastLoginDate { get; set; }
}
所以,正如你在这里看到的,不是在模型中创建一个LastLoginDate属性,而是需要映射回数据存储,我们在partial类中创建了属性,然后我们可以选择填充在 对象实现 或 按需 期间,如果您不相信每个实体对象都需要提供信息。
在您的情况下,为每个实现的 User 预先计算 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;
}
}
最后一步(实际工作)将实现此处理程序以实际填充我们的自定义属性,在这种情况下非常简单:
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);
}
}
希望这会有所帮助。
答案 1 :(得分:1)
经过深思熟虑,我最终得到了以下解决方案:
首先,创建一个包含所有用户字段和LastLogin日期字段的视图(来自我的原始帖子)。
将用户(称之为 User_Model )和用户视图(称之为 UserView_Model )添加到我的EF模型后,我创建了一个包装类(称之为 User_Wrapper )围绕User_Model并为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>。
缺点?我想这是因为我的UserView_Model没有任何关联关系,我将无法使用EF ObjectContext进行任何急切的加载。幸运的是,在我的情况下,我认为这不是一个问题。
有更好的方法吗?
答案 2 :(得分:1)
我只是遇到了两个相关实体需要计数属性而不加载集合的情况。我发现的一件事是你需要在连接字符串中使用MultipleActiveResultSets = True,以避免在查询其他实体集时在ObjectMaterialized事件处理程序上抛出异常。