Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF codefirst : Should I initialize navigation properties?

I had seen some books(e.g programming entity framework code first Julia Lerman) define their domain classes (POCO) with no initialization of the navigation properties like:

public class User {     public int Id { get; set; }     public string UserName { get; set; }      public virtual ICollection<Address> Address { get; set; }     public virtual License License { get; set; } } 

some other books or tools (e.g Entity Framework Power Tools) when generates POCOs initializes the navigation properties of the the class, like:

public class User {     public User()     {         this.Addresses = new IList<Address>();         this.License = new License();     }     public int Id { get; set; }     public string UserName { get; set; }      public virtual ICollection<Address> Addresses { get; set; }     public virtual License License { get; set; } } 

Q1: Which one is better? why? Pros and Cons?

Edit:

public class License {     public License()     {         this.User = new User();     }     public int Id { get; set; }     public string Key { get; set; }     public DateTime Expirtion { get; set; }      public virtual User User { get; set; } } 

Q2: In second approach there would be stack overflow if the `License` class has a reference to `User` class too. It means we should have one-way reference.(?) How we should decide which one of the navigation properties should be removed?

like image 772
Iman Mahmoudinasab Avatar asked Dec 24 '13 08:12

Iman Mahmoudinasab


People also ask

What is navigation property in Entity Framework?

A navigation property is an optional property on an entity type that allows for navigation from one end of an association to the other end. Unlike other properties, navigation properties do not carry data. A navigation property definition includes the following: A name. (Required)

Does EF core need empty constructor?

When constructor parameters cannot be bound to properties, the Entity Framework requires an empty constructor. This happens for example when your constructor parameter is a navigation property. In this case EF will go via the emtpy constructor and bind the property directly.

How do I load navigation properties in Entity Framework Core?

You can explicitly load a navigation property via the DbContext. Entry(...) API. You can also explicitly load a navigation property by executing a separate query that returns the related entities.

Does EF core call constructor?

It's possible to define a constructor with parameters and have EF Core call this constructor when creating an instance of the entity. The constructor parameters can be bound to mapped properties, or to various kinds of services to facilitate behaviors like lazy-loading.


1 Answers

Collections: It doesn't matter.

There is a distinct difference between collections and references as navigation properties. A reference is an entity. A collections contains entities. This means that initializing a collection is meaningless in terms of business logic: it does not define an association between entities. Setting a reference does.

So it's purely a matter of preference whether or not, or how, you initialize embedded lists.

As for the "how", some people prefer lazy initialization:

private ICollection<Address> _addresses;  public virtual ICollection<Address> Addresses {      get { return this._addresses ?? (this._addresses = new HashSet<Address>()); } 

It prevents null reference exceptions, so it facilitates unit testing and manipulating the collection, but it also prevents unnecessary initialization. The latter may make a difference when a class has relatively many collections. The downside is that it takes relatively much plumbing, esp. when compared to auto properties without initialization. Also, the advent of the null-propagation operator in C# has made it less urgent to initialize collection properties.

...unless explicit loading is applied

The only thing is that initializing collections makes it hard to check whether or not a collection was loaded by Entity Framework. If a collection is initialized, a statement like...

var users = context.Users.ToList(); 

...will create User objects having empty, not-null Addresses collections (lazy loading aside). Checking whether the collection is loaded requires code like...

var user = users.First(); var isLoaded = context.Entry(user).Collection(c => c.Addresses).IsLoaded; 

If the collection is not initialized a simple null check will do. So when selective explicit loading is an important part of your coding practice, i.e. ...

if (/*check collection isn't loaded*/)     context.Entry(user).Collection(c => c.Addresses).Load(); 

...it may be more convenient not to initialize collection properties.

Reference properties: Don't

Reference properties are entities, so assigning an empty object to them is meaningful.

Worse, if you initiate them in the constructor, EF won't overwrite them when materializing your object or by lazy loading. They will always have their initial values until you actively replace them. Worse still, you may even end up saving empty entities in the database!

And there's another effect: relationship fixup won't occcur. Relationship fixup is the process by which EF connects all entities in the context by their navigation properties. When a User and a Licence are loaded separately, still User.License will be populated and vice versa. Unless of course, if License was initialized in the constructor. This is also true for 1:n associations. If Address would initialize a User in its constructor, User.Addresses would not be populated!

Entity Framework core

Relationship fixup in Entity Framework core (2.1 at the time of writing) isn't affected by initialized reference navigation properties in constructors. That is, when users and addresses are pulled from the database separately, the navigation properties are populated.
However, lazy loading does not overwrite initialized reference navigation properties.

In EF-core 3, initializing a reference navigation property prevents Include from working properly.

So, in conclusion, also in EF-core, initializing reference navigation properties in constructors may cause trouble. Don't do it. It doesn't make sense anyway.

like image 139
Gert Arnold Avatar answered Oct 05 '22 20:10

Gert Arnold