Reputation: 326
I'm having trouble pulling a ApplicationUser
object in a query to the DbContext
.
Here is my Foo
model
public class Foo
{
public int Id { get; set; }
public string Title { get; set; }
public ApplicationUser Creator { get; set; }
}
Inside of my Foo controller in the edit action I want to check that the User requesting the edit is the Creator.
//ApplicationDbContext inherits IdentityDbContext
private ApplicationDbContext appDb { get; set; }
...
public async Task<ActionResult> Edit(int? id)
{
Foo target = appDb.Foos.First(o => o.Id == id);
if (target == null)
{
return HttpNotFound();
}
if (target.Creator.Id != User.Identity.GetUserId())
{
ViewBag.Error = "Permission denied.";
return Redirect(Request.UrlReferrer.ToString());
}
return View(target);
}
The problem is that for some reason target.Creator
returns null, although all Foo
have a Creator
object referenced. In the same controller, in the details action it gets pulled just fine:
var entry = appDb.Foos.Where(f=>f.Id == id)
.Select(foo => new FooViewModel()
{
Id = foo.Id,
Title = foo.Title,
CreatorId = foo.Creator.Id,
CreatorName = foo.Creator.FirstName,
}).FirstOrDefaultAsync();
What am I missing? What is so different about trying to access foo.Creator
inside of the Display query than trying to access it directly on a Foo object? I thought EF would have queried for foo.Creator
when I requested the Foo itself.
Should I change foo.Creator
to store foo.CreatorId
instead?
Thanks.
Upvotes: 3
Views: 59
Reputation: 39055
The navigation properties are not feched by default. If you need them, eager load them using .Include()
:
Foo target = appDb.Foos.First(o => o.Id == id).Include(f => f.Creator);
Your code will not work at all: if you try to find the first element, with .First()
and it doesn't exist, you'll get an exception. I.e, your code will never hit if (target == null)
.
You should use .FirstOrDefault()
, or better thant that, Find()
.
Upvotes: 4
Reputation: 3726
you need eager loading -
var returned = appDb.Foos.First(o => o.Id == id).Include(a => a.Creator);
On the other hand, you could use Lazy Loading
by marking the ApplicationUser
member as virtual.
Upvotes: 2