Mathieu
Mathieu

Reputation: 1677

Null navigation properties using OData/Entity Framework

I have a database schema (MySql) exposed as a data/OData service that is queried by my Silverlight client using Linq. Here is the model in question: enter image description here

The columns Level and Application are Int values referencing via a foreign key the tables lookuplevel and lookuppid respectively.

So, an entry in the logstest table may look like this:

ID:35
Date: 2012-02-29
Level: 1
Application: 1
Message: MyMessage
Exception: MyException
ReverseOrder: 56 (don't mind this column)

And we could have in lookuplevel:

ID: 1
String: Warning

And in lookuppid

ID: 1
String: Product A

As you can see, the Level and Application columns are actually mapped to a value in there referenced table.

Now client side (Silverlight), I get the content of the logstest table via a linq query.

public void LoadErrors()
{
   var linqQuery = (from e in _myEntities.logstests
                    select e);

   AsyncCallback GetDataComplete = new AsyncCallback(MyCallback);
           ((DataServiceQuery<logstest>)linqQuery).BeginExecute(GetDataComplete, linqQuery);
}

private void MyCallback(IAsyncResult asyncResult)
{
    DataServiceQuery<logstest> query = asyncResult.AsyncState as DataServiceQuery<logstest>;

    foreach (logstest error in e.Query.EndExecute(e.Result))
    {
        Error newError = new Error
        {
            Date = error.Date,
            Level = error.lookuplevel.String,
            Application = error.lookuppid.String,
            Message = error.Message,
            Exception = error.Exception
        };
    }

    // Do more stuff...
}

Error is a custom class that is binded on a datagrid that displays each field in a separate column.

Obviously, for the columns Level and Application, I do not want to display the index of the value they reference but the value itself (ie: for Level I want to display Warning and not 1).

The problem is that both error.lookuplevel and error.lookuppid are null and I have no idea why. Is there a gotcha somewhere that I don't know about?

Thanks in advance!

Upvotes: 2

Views: 3119

Answers (3)

Vitek Karas MSFT
Vitek Karas MSFT

Reputation: 13320

You must explicitely ask to include the related entity, otherwise WCF DS Client will not ask for it on the server. And it also doesn't do lazy loading of the navigation properties, since the lazy load would have to invoke an HTTP request which can take a really long time, and so it's not a good idea to do that inside a property getter.

To ask to include related entities, you need to add $expand to the query, like this:

var linqQuery = (from e in 
   _myEntities.logstests.Expand("lookuppid").Expand("lookuplevel")  
   select e); 

Upvotes: 4

Matija Grcic
Matija Grcic

Reputation: 13381

Please install EF 4.1 from http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8363 to stop using magic strings inside Include. Add

using System.Data.Entity;

to your using statements.

Then write the following query:

var linqQuery = _myEntities.logstests.Include(e=>e.lookuppid).Include(e=>e.lookuplevel);

For more information refer to the following http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx

Upvotes: 0

kprobst
kprobst

Reputation: 16651

Normally in EF if you don't have lazy loading enabled in the context you need to include the navigation property by name in the query:

var linqQuery = (from e in
   _myEntities.logstests.Include("lookuppid").Include("lookuplevel") 
   select e);

Upvotes: 0

Related Questions