简体   繁体   中英

EF 6 codde first - One To Many Mapping - ICollection always null

I know this question was asked many times before, but I have a strange behavior at my side and I couldn't get any solution.

I'm building a .Net application with EF6 and code first. I defined my classes as follows (these are example classes but I have exactly the same structure):

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int RefId { get; set; }

    public int GradeId { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{
    private string _name;

    public int GradeId { get; set; }
    public string GradeName { get; set; }

    public ICollection<Student> Students { get; set; }
}

I understand that lazy loading is enabled by default beyond ef 4, and the solution that mostly work is to remove the virtual keyword from the entities (non-virtual properties).

In my case, I want to set some custom code in the getter method of the Grade class, but ICollection<Student> Students is always null.

For example:

public string GradeName
{
    get
    {
        _name = Students.FirstOrDefault(s => s.GradeId == GradeId &&
                              s.RefId == 2).Name;

        if (string.IsNullOrWhiteSpace(_name))
        {
            _name = Name;
        }

        return _name;
    }

    set => _name = value;
}

I tried everything possible, nothing helped. It will be great if you can help me solve this issue, thanks!

You are misunderstanding how lazy vs eager loading works. See here .

Marking the collection virtual just means it is deferred. Removing it does not populate the collection, you still need the Include:

var studentWithGrade = context.Students
            .Include(s => s.Grade)
            .FirstOrDefault(s => s.GradeId == GradeId && s.RefId == 2);

or the grade with the student collection:

var gradeWithStudents = context.Grade
            .Include(g => g.Students)
            .ToList();

More include combinations here .

You should initialize students in the constructor as it's responsibility of the class:

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }

    public ICollection<Student> Students { get; set; }

    public Grade ()
    {
        Students = new Collection<Student>();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM