EF codefirst: Should I initialize the navigation properties?

I saw some books (for example, Julia Lerman's code of the entity entity framework first) defines her domain classes (POCO) without initializing navigation properties, such as:

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 (for example, Entity Framework Power Tools) when creating POCOs initialize the navigation properties for the class, for example:

 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? What for? Advantages and disadvantages?

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 the second approach, a stack overflow occurs if the `License` class also refers to the` User` class. This means that we must have a one-way link. (?) How should we decide which of the navigation properties should be removed?

+52
c # entity-framework domain-driven-design ef-code-first navigation-properties
Dec 24 '13 at 8:39
source share
6 answers

Collections: It doesn't matter.

There is a clear distinction between collections and links as navigation properties. A link is an object. Collections contain objects. This means that initializing the collection is pointless from the point of view of business logic: it does not determine the relationship between entities. Link setting is in progress.

So this is solely a matter of preference, whether you are or not, or how you initialize inline 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 unnecessary reference exceptions, so it facilitates unit testing and assembly control, but also prevents unnecessary initialization. The latter can make a difference when a class has relatively many collections. The disadvantage is that relatively much plumbing is required, especially. Compared to auto properties without initialization. In addition, the emergence of the null distribution operator in C # made initialization of collection properties less relevant.

... if explicit loading is not applied

The only thing that initializing collections makes it difficult to verify if the assembly has been loaded by the Entity Framework. If the collection is initialized, a statement like ...

 var users = context.Users.ToList(); 

... will create User objects that have empty, but not null Addresses collections (deferred loading). Checking if a collection is loaded requires code ...

 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 be performed. Therefore, when selective explicit loading is an important part of your coding practice, that is ...

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

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

Initial Properties: Not

Reference properties are objects, so assigning an empty object to them makes sense .

Even worse, if you initiate them in the constructor, EF will not overwrite them when materializing your object or lazy loading. They will always have their initial values ​​until you replace them. What's worse, you can even save empty objects in the database!

And there is another effect: the correction of relations will not occur. Link fixing is the process by which EF connects all objects in a context using its navigation properties. When User and Licence are loaded separately, still User.License will be filled in and vice versa. Unless, of course, if License was not initialized in the constructor. This is true for 1: n associations. If Address will initialize User in its constructor, User.Addresses will not be populated!

Entity Framework Kernel

Fixing relations in the kernel of the Entity Framework (2.1 at the time of writing) does not affect the initialized properties of link navigation in constructors. That is, when users and addresses are retrieved from the database separately, the navigation properties are populated.
However, lazy loading does not overwrite the initialized navigation links of the property. So, in conclusion, as well as in the EF kernel, initializes the links of navigation properties in the constructors can cause problems. Do not do this. In any case, it doesn’t make sense,

+62
Dec 25 '13 at 13:00
source share

In all my projects, I follow the rule - "Collections should not be empty. They are either empty or have meaning."

The first example is possible when the creation of these objects is the responsibility of the third part code (for example, ORM), and you are working on a short-term project.

The second example is better since

  • are you sure that the object has all the properties set
  • you avoid nonsense NullReferenceException
  • you make your code consumers happier

People who practice domain-driven design exhibit read-only collections and avoid installing on them. (see What works best for readonly lists on NHibernate )

Q1: Which one is better? What for? Advantages and disadvantages?

It is better to set non-null combinations, since you avoid additional code checks (e.g. Addresses ). This is a good contract for your code base. But I just need to show a reference link to a single entity (e.g. License )

Q2: in the second approach, a stack overflow occurs if the License class has a reference to the User class. This means that we must have a one-way link. (?) How should we decide which of the navigation properties should be removed?

When I independently developed a sample data map , I tried to avoid bidirectional links and very rarely referred to child and parent links.

When I use ORM, it is easy to have bidirectional links.

When you need to create a test object for my unit tests with a bi-directional set of links, I follow these steps:

  • I am building a parent entity with an emty children collection .
  • Then I add an evey child with a link to the parent entity in the children collection .

If you have a parametric constructor in License , type I should make User property mandatory.

 public class License { public License(User user) { this.User = user; } public int Id { get; set; } public string Key { get; set; } public DateTime Expirtion { get; set; } public virtual User User { get; set; } } 
+4
Dec 25 '13 at 10:54
source share

It is redundant for the new list, since your POCO depends on Lazy Loading.

Lazy loading is a process in which an entity or set of objects is automatically loaded from the database upon first access to an object related to an object / objects. When using POCO entity types, lazy loading is achieved by instantiating derived proxy types and then overriding virtual properties to add a boot hook.

If you remove the virtual modifier, you will disable lazy loading, in which case your code will no longer work (because nothing will initialize the list).

Note that Lazy Loading is a feature supported by the entity framework, if you create a class outside the DbContext context, then the dependent code obviously suffers from a NullReferenceException

NTN

+3
Dec 24 '13 at 10:17
source share

Q1: Which one is better? What for? Advantages and disadvantages?

The second option, when virtual properties are set inside the constructor of the entity, has a certain problem, which is called " Virtual call of the participant in the constructor .

As for the first option, without initializing the navigation properties, depending on who / what creates the object, there are 2 situations:

  • Entity structure creates an object
  • Code user creates an object

The first option is perfectly correct when the Entity Framework creates an object, but can fail when a code user creates an object.

The solution to ensure that the code consumer always creates a valid object is to use the static factory method:

  • Make the default security constructor. Entity Framework works great with protected constructors.

  • Add a static factory method that creates an empty object, for example. a User , sets all properties, for example. Addresses and License after creation and returns a fully constructed User object

Thus, the Entity Framework uses the default protected constructor to create a valid object from data obtained from some data source, and the code consumer uses the static factory method to create a valid object.

+3
Sep 20 '15 at 13:19
source share

I am using the answer from this Why is my Entity Framework Code First proxy null and why can not I install it?

There were problems with initializing the constructor. The only reason I do this is to make the test code easier. After making sure that the collection is never null, I constantly change the initialization in tests, etc.

+2
Dec 24 '13 at 10:24
source share

The other answers fully answer the question, but I would like to add something, since this question still matters and appears in a Google search.

When you use the "First Model from Database" wizard in Visual Studio, all collections are initialized as follows:

 public partial class SomeEntity { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public SomeEntity() { OtherEntities = new HashSet<OtherEntity>(); } public int Id { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection<OtherEntity> OtherEntities { get; set; } } 

As a rule, I get a master result, because basically it is an official recommendation from Microsoft, so I add to this five-year question. Therefore, I would initialize all collections as a HashSet .

And personally, I think it would be nice to tweak this to take advantage of the C # 6.0 auto-source initializers:

  public virtual ICollection<OtherEntity> OtherEntities { get; set; } = new HashSet<OtherEntity>(); 
0
Apr 10 '18 at 15:38
source share



All Articles