1

I'm working on a code-first EF6 project using MySql. I have setup my data classes such that their related data objects should be lazy-loaded, but they seem to run very slowly each time they are called.

This is an example of one of my entity classes:

[Table("Carrier")]
public class DBCarrier
{
    [Key]
    [Column("CarrierId")]
    public int carrierId { get; set; }

    [MaxLength(128), Required]
    public string CarrierName { get; set; }

    public virtual ICollection<DBDepot> Depots { get; set; }
    public virtual ICollection<DBZone> Zones { get; set; }
}

But when I call the Zones on an object of this class like this (this was all in one statement, but I separated it out to try and find out where the problem was):

ICollection<DBZone> zones = carrier.Zones;
IEnumerable<DBZone> zones1 = zones.Where(x => x.Postcode == postcode);
return zones.Select(x => x.ZoneName).FirstOrDefault();

Every time I call carrier.Zones it takes about 8 seconds to run. I thought that by defining zones as an ICollection would delay execution of the database query.

1 Answer 1

2

ICollection means the data is definitely already materialized in memory. The only way to get your desired behavior is to use an interface which supports deferred execution and there's only two:

  • IQueryable the query is built up using Expressions and is used to fire queries upon remote data sources (for example sql database).
  • IEnumerable the query is built up using Delegates and is used to fire queries upon datasets already in memory.

Using any of these 2 interface types will cause your query to be executed when you iterate the data using First(), FirstOrDefault(), ToList() or ToArray().

But seeing you only need the names of the zones your query is pretty inefficient. You fetch the whole DBZone object but you only take the name, I would suggest just fetching the names:

return carrier.Zones.FirstOrDefault(z => z.Postcode == postcode).Select(z => z.ZoneName);

For this you need to keep carrier as an IQueryable of course.

Edit: Just noticed "Every time I call carrier.Zones it takes about 8 seconds to run."

This is the expected behavior for lazy loading. The data will get fetched from the database when you access it => Database call for the carrier, and another call to database for the zones when you access them. This can be avoided using eager loading (Include method) to get all the desired data in one trip to the database.

Sign up to request clarification or add additional context in comments.

1 Comment

Makes sense. I will try that later.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.