Mohammed Noureldin
Mohammed Noureldin

Reputation: 16806

EF: Navigation property is null even after accessing it or removing virtual keyword

I am new to entity framework (core), I am facing some problem related to lazy loading as I think.

I have the following simple data model with one to one relationship:

User ----- AccessToken

User:

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }

    public virtual AccessToken AccessToken { get; set; }
}

AccessToken:

public class AccessToken
{
    public int Id { get; set; }
    public string Token { get; set; }

    [ForeignKey("User"), Required]
    public int UserId { get; set; }
    public virtual User User { get; set; }
}

Now when I trying to get the AccessToken of a User using the User's navigation property it is always null:

var t1 = Context.Find<User>(user.Id);
var t2 = t1.AccessToken;
var t3 = Context.Find<User>(user.Id).AccessToken;

I also tried to remove virtual keyword from the navigation properties with no success.

Would some one help me to solve that problem please?

Upvotes: 0

Views: 1669

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109080

First, this is not a 1:1 relationship. As for the database, there can be multiple AccessTokens with the same UserId, i.e. it's a 1:n relationship. To turn it into a real 1:1 relationship, your model should look like this:

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }

    public virtual AccessToken AccessToken { get; set; }
}

public class AccessToken
{
    [ForeignKey("User")]
    public int Id { get; set; }
    public string Token { get; set; }

    public virtual User User { get; set; }
}

Now any AccessToken will have a PK that's identical to its User's PK, so it's unique and tied to only one user.

Next, as said in the comments, lazy loading is not yet supported in EF core. Until it is (if ever?) you have to use Include (eager loading) ...

using (var db = new MyContext())
{
    var user = db.Users.Include(u => u.AccessToken)
                 .Single(u => u.Id == 1);
}

... or load the data separately (eplicit loading):

    db.AccessTokens.Where(a => a.Id == 1).Load();
    var user = db.Users
                 .Single(u => u.Id == 1); // Or db.Users.Find(1)

In the latter case, EF will connect the user and its token by relationship fixup.

Upvotes: 2

Related Questions