user1854458
user1854458

Reputation: 665

Entity Framework one-to-one relationships

I'm having some issues with understanding how to property set up one-to-one relationships for a Web API using Entity Framework Core.

Consider the following objects:

public class Car
{  
    [JsonIgnore]
    public Int32 CarId { get; set; }

    public virtual Horn Horn { get; set; }
    public virtual ICollection<Wheel> Wheels { get; set; }
}

public class Horn
{
    [JsonIgnore]
    public Int32 HornId { get; set; }
    public Sound Sound { get; set; }
}

public class Sound
{
    // some other props
}

When I perform a query in my repository, one-to-many is by default excluded unless I use .Include(), however, for one-to-one properties, they are by default included when I serialize.

e.g. It gets really messy because I query for a car and it returns all it's sub-components in the JSON response.

I can set car.Horn = null, etc, but that seems difficult to maintain for complex objects. I would like it to function like .Include(), but by default be excluded (in case I do want to query the full object).

Edit: Note, this issue is recursive, the car pulls in horn which pulls in sound. On a real world example like a user table, the automatically pulled in data when serialized is huge unless specifically nullifying the child properties.

EDIT2:

Here is an example of a repository call that by default bring back all one-to-one properties:

var group = _context.Car.Include(c => c.Wheels).SingleOrDefault(u => u.CarId == id);

Note the Include works as expected for many-to-one, but this query, even when the Include is removed, will recursively return all child objects that are one-to-one.

It does appear some type of lazy loading is being introduced in EF CORE 2.1

Upvotes: 0

Views: 390

Answers (2)

Aistis Taraskevicius
Aistis Taraskevicius

Reputation: 811

Context mapping

   modelBuilder.Entity<SessionFeedbackModel>(entity =>
        {
            entity.HasOne(s => s.Session).WithOne(p => p.Feedback)
                .HasForeignKey<SessionFeedbackModel>(s => s.SessionId).OnDelete(DeleteBehavior.Restrict);
        });

        modelBuilder.Entity<SessionQuestionModel>(entity =>
        {
            entity.HasOne(e => e.SessionResult).WithOne(e => e.SessionQuestion)
                .HasForeignKey<SessionQuestionResultModel>(e => e.SessionQuestionId)
                .OnDelete(DeleteBehavior.Restrict);

        });

Models

   public class SessionQuestionResultModel
    {
        public int Id { get; set; }

        public int SessionQuestionId { get; set; }

        public SessionQuestionModel SessionQuestion { get; set; }
    }


    public class SessionFeedbackModel
    {
        public int Id { get; set; }
        public int SessionId { get; set; }

        public SessionModel Session { get; set; }

    }

EF Core 1.x or 2.x does not support 1 to 1 very well or at all, but it can be done this way, this would be radically different for EF 6.x.x

Upvotes: 0

Bobo
Bobo

Reputation: 335

This article should give you a hint. https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx Mainly:

Turn lazy loading off for serialization

Lazy loading and serialization don’t mix well, and if you aren’t careful you can end up querying for your entire database just because lazy loading is enabled. Most serializers work by accessing each property on an instance of a type. Property access triggers lazy loading, so more entities get serialized. On those entities properties are accessed, and even more entities are loaded. It’s a good practice to turn lazy loading off before you serialize an entity. The following sections show how to do this.

EDIT: Here is the way to disable lazy loading for all entities. But note you have to achieve this several way, so check the other options in the article...

public class YourContext : DbContext 
{ 
    public YourContext() 
    { 
        this.Configuration.LazyLoadingEnabled = false; 
    } 
}

Upvotes: 1

Related Questions