4
votes

I have a poco class which is wired up to the entity framework. The class is called PersonalizationCatalogPrice. This class has a sub object called Pricelevel which does not have the virtual keyword on it. Because of this (based on my understanding) this object should never lazy load and should return null. However, we have found that this object seems to load up when used in a specific manner.

so the basic class structure is this

public class PersonalizationCatalogPrice
    {
        public int PersonalizationCatalogPriceID { get; set; }

        public int PersonalizationCatalogId { get; set; }

        public virtual PersonalizationCatalog PersonalizationCatalog { get; set; }

        public decimal CustomerRetail { get; set; }

        public decimal ConsultantCost { get; set; }

        public decimal PersonalVolume { get; set; }

        public decimal QualifyingVolume { get; set; }

        public int PriceLevelId { get; set; }

        public PriceLevel PriceLevel { get; set; }
}

Here is an example. In the first line we return an Iqueryable of PersonalizationCatalogPrice items. In the second line we have another IQueryable and we are using the priclevel object in this iQueryable (see the line "contains pcp.pricelevel"). When we do this, the pricelevel object loads up even though it has no virtual keyword.

IQueryable<PersonalizationCatalogPrice> allPersPriceRecords = _e2ReposMan.PersonalizationRepository.GetSomeRecords();

//List<PersonalizationCatalogPrice> persprices = allPersPriceRecords.ToList();

var persQuery = from pl in personalizationLines
                join pcp in allPersPriceRecords on pl.Item2.PersonalizationCatalogPriceID equals pcp.PersonalizationCatalogPriceID
                where !HostessPriceLevelTypes().Contains(pcp.PriceLevel.PriceLevelTypeId)
                select pl.Item2.PersonalVolume * pl.Item1;

var openOrdersTotal = (query.Any() ? query.Sum() : 0) + (persQuery.Any() ? persQuery.Sum() : 0);

Modifying this code by uncommenting the second line which performs a ToList() however. Makes the pricelevel subobject return null as expectedd since it does not have a virtual keyword on it and the entity framework then works as we anticipate. (EF 6)

Does anyone know why we are able to load the pricelevel property when we do not do the toList().

thanks for any assistance.

1
"Pricelevel which does not have the virtual keyword on it. Because of this (based on my understanding) this object should never lazy load " - virtual is used for lazy loading. You also need to check your context LazyLoadingEnabled setting. Finally, you are accessing PriceLevel in your query so shouldn't it load up? Maybe im not clear on the issue. msdn.microsoft.com/en-us/data/jj574232.aspx#lazySteve Greene
It should if you have it defined as virtual which we don't. Because of this is should be null. If i add virtual to it then it should load up when it is accessed..that is the 'lazy load'..dont load until it is needed. But this property is loading up when it is accessed as if it is defined as a virtual property and it is not. Also, Our context does allow lazy loadingMatt
The property is going to "load up" when accessed whether it's lazy(virtual) or not. The lazy part kicks in if it is virtual, lazy loading is enabled and you never access the property.Steve Greene
My guess would be this: allPersPriceRecords is an IQueryable<> which, unless "executed" (by, e.g. enumeration), will be treated as LINQ to Entities query, and will be "translated" into a (SQL) query - i.e. accessing particular navigation properties will result in extra joins in the query. But once you "execute" it (by calling ToList()) it's results will be cached, and from that point it no longer will be "executed", i.e. whenever you access it's results you'll be in fact using LINQ to Objects, and not LINQ to Entities. But, as I mentioned, its just my guess.Grx70

1 Answers

1
votes

Based on the wording you used, it appears that you expect the PriceLevel property to be null when not using lazy loading.

There are some cases i can think of, in which this expectation would not be met.

The first case would be if you are loading the data in a eager way. Which would be explicitly using Include(). This behaviour is also called eager loading. Since eager loading does load everything it is allowed to, it does not require you to enumerate the collection by calling ToArray() or ToList() or other methods that trigger enumeration. Every property which is not lazy will be loaded, that includes all its value type properties and non-lazy properties.

Your code does not indicate this, however the property would still not be null if you did this on the same DbContext derived instance before executing the code you displayed. This would happen whenever the entity in question already resides cached in your DbContext.

The same would be true if you had loaded that entity explicitly by calling Load() or if it had been returned from some other previous query.

In order to verify whether this is the case or not you can use the AsNoTracking() extension method. Entities which are not tracked will, among other effects, not be linked with each other.