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,[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模型以包含计算的列?
解决方法
自定义属性是一种向实体提供计算属性的方法.好消息是,自定义属性不一定需要从同一个实体上的其他现有属性计算,通过我们即将看到的代码,它们可以从我们喜欢的任何东西计算出来!
以下是步骤:
首先创建一个分部类并在其上定义一个自定义属性(为简单起见,我假设User_User表已映射到User类,Util_Login已映射到Util)
public partial class User { public DateTime LastLoginDate { get; set; } }
所以,正如你在这里看到的,不是在模型中创建一个LastLoginDate属性,而是需要映射回数据存储,我们在partial类中创建了属性,然后我们可以选择在对象期间填充它如果您不相信每个实体对象都需要提供该信息,则实现或按需提供.
在您的情况下,预先计算每个正在实现的用户的LastLoginDate自定义属性是有用的,因为我认为将为所有(或至少大多数)实体实现此值.否则,您应该考虑仅在需要时而不是在对象实现期间计算属性.
为此,我们将利用ObjectContext.ObjectMaterialized Event,这是从查询返回数据时引发的,因为ObjectContext正在从该数据创建实体对象. ObjectMaterialized事件是一个Entity Framework 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); } }
希望这可以帮助.