Very good question, and Yes, there is a perfect way to accomplish this in EF4:
Custom properties are a way to provide computed properties to entities. The good news is that Custom properties don’t necessarily need to be calculated from other existing properties on the very same entity, by the code we are about to see, they can computed from just about anything we like!
Here are the steps:
First create a partial class and define a custom property on it (For simplicity, I assumed *User_User* table has been mapped to User class and *Util_Login* to Util)
public partial class User {
public DateTime LastLoginDate { get; set; }
}
So, as you can see here, rather than creating a LastLoginDate property in the model, which would be required to map back to the data store, we have created the property in the partial class and then we have the option to populate it during object materialization or on demand if you don’t believe that every entity object will need to provide that information.
In your case precalculating the LastLoginDate custom property for every User being materialized is useful since I think this value will be accessed for all (or at least most) of the entities being materialized. Otherwise, you should consider calculating the property only as needed and not during object materialization.
For that, we are going to leverage ObjectContext.ObjectMaterialized Event which is raised anytime data is returned from a query since the ObjectContext is creating the entity objects from that data. ObjectMaterialized event is an Entity Framework 4 thing.
So all we need to do is to create an event handler and subscribe it to the ObjectMaterialized Event.
The best place to put this code (subscribing to the event) is inside the OnContextCreated Method. This method is called by the context object’s constructor and the constructor
overloads which is a partial method with no implementation, merely a method signature created by EF code generator.
Ok, now you need to create a partial class for your ObjectContext. (I assume the name is UsersAndLoginsEntities) and subscribe the event handler (I named it Context_ObjectMaterialized) to ObjectMaterialized Event.
public partial class UsersAndLoginsEntities {
partial void OnContextCreated() {
this.ObjectMaterialized += Context_ObjectMaterialized;
}
}
The last step (the real work) would be to implement this handler to actually populate the Custom Property for us, which in this case is very easy:
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);
}
}
Hope this helps.