views:

52

answers:

2

I have three related entities, best described by this diagram:

alt text

When I load a user, using the following code, the User object is loaded, i.e. not null, but the Role and Department properties on the User object are null, despite User database record having valid FK values for these associations.

using (var productionEntities = new ProductionEntities())
{
    var userName = GetUserName();
    User u = (from usr in productionEntities.UserSet
              where usr.UserName == userName
              select usr).FirstOrDefault();
    if (u == null)
    {
        throw new KpiSecurityException("No local database entry found for user.") { UserName = userName };
    }
    return u.Department.DeptName;
}

ASIDE: I went through this whole mission just because the ASP.NET MembershipProvider doesn't support user 'metadata' like department, and I would have had to use the ProfileProvider as well, at the cost of immense DB bloat.

+3  A: 

Hi, you must explicitly load this properties

User u = (from usr in productionEntities.UserSet
          where usr.UserName == userName
          select usr).FirstOrDefault();

if (u == null)
{
        throw new KpiSecurityException("No local database entry found for user.") { UserName = userName };
}

if (!u.RoleReference.IsLoaded)
{ u.RoleReference.Load(); }

if (!u.DeparmentReference.IsLoaded)
{ u.DeparmentReference.Load(); }

or include this entities in your query

User u = (from usr in productionEntities.UserSet.Include("Role").Include("Department")
          where usr.UserName == userName
          select usr).FirstOrDefault();
Jan Remunda
That will result in three DB queries; only one is needed.
Craig Stuntz
If you use "Include", EF generates one query..
Jan Remunda
+1 for teaching me the IsLoaded and Load() members. I knew there was something like that, but I just didn't know where to look for it.
ProfK
Ishtar, `Load()` generates too many queries, and `Include` generates overly complicated queries. Either way, you're making the DB server work harder than necessary to return one single field.
Craig Stuntz
Craig: But the question was about loading referenced properties, not about selecting one single field. And in LINQ to Entities isn't imho other right way to do this. Using stored procedures for listing and selecting would be counter-productive.
Jan Remunda
His method returns one field. Why select anything else. Nobody suggested stored procs; that would be a waste of effort. L2E already handles this fine. I don't know why you'd want to execute a query (or queries!) which return dozens of properties from multiple objects when you only need one value returned from the method.
Craig Stuntz
+1  A: 

Since you only need the department name, just project that out; this way you query the DB only once:

using (var productionEntities = new ProductionEntities())
{
    var userName = GetUserName();
    var u  = (from usr in productionEntities.UserSet
              where usr.UserName == userName
              select new
              {
                  DeptName = usr.Department.DeptName
              }).FirstOrDefault();
    if (u == null)
    {
        throw new KpiSecurityException("No local database entry found for user.") { UserName = userName };
    }
    return u.DeptName;
}
Craig Stuntz