I am loading data from an external source as xml, it gets deserialized and then I loop over the object to funnel them into my domain entities.
In order to create the relationships between data and cut down on database calls I wrote an extension method to attempt to retrieve items from DbSet.Local first if it doesnt find the item then it uses DbSet.SingleOrDefault() to query the database as shown below.
public static TEntity SingleOrDefaultLocalFirst<TEntity>(this IDbSet<TEntity> set,
Func<TEntity, bool> predicate) where TEntity : class
{
if (set == null)
throw new ArgumentNullException("set");
if (predicate == null)
throw new ArgumentNullException("predicate");
TEntity results = null;
try
{
results = set.Local.SingleOrDefault(predicate);
}
catch (Exception e)
{
Debug.WriteLine(e.Message, "Error");
}
if (results != null)
{
return results;
}
return set.SingleOrDefault(predicate);
}
The try catch block is there to suppress the problem I am trying to fix.
For some reason the navigation properties when querying the local store are not populated. So if I use something like
(x=>x.Participant.Event.ExternalId==newItem.Id)
as my lambda, the Participant nav property is null.
I feel like there should be some way to get this code to not consistently generate null reference errors.
I have tried explicitly loading the Participant and Event data from the database before my loop starts using
context.Participant.Load()
but this makes no difference.
Can someone tell me why the navigation properties are null and how to populate them the most efficient way?
And, if anyone is wondering why I am not using Find(), it is because the external data is keyed on a number of properties as well as an external id field which is not the primary key in my system.
Update:
Im not going to take the time to include my real code because there is just too much to whittle down to a usable example so I will try and use the Customer/Order/OrderItem typical example.
The real issue is that when you have a nested entity and you try and check for existence using something like:
var orderLine = context.OrderLineItems.Local.SingleOrDefault(x=>x.Order.Number == 1234)
it will throw a nullreference error for Order even if the Orders and Customers are loaded explicitly into the context prior to this using
context.Orders.Load()
But, if you do this:
var orderLine = context.OrderLineItems.SingleOrDefault(x=>x.Order.Number == 1234)
it will work.
I want to understand why it doesnt work when calling Local. Why should we have to make a trip to the database to get the related nav properties when they already have been loaded into the context? or am I missing something?