Your Address class already has a State property that represents the relation. Why don't you just use that?
public IQueryable<string> Addresses()
{
var query = from a in _contextProvider.Context.Addresses
where a.CityName.StartsWith("I")
select a.State.StateName;
return query;
}
Update:
From your latest comment I guess you turned off lazy loading for your model by setting LazyLoadingEnabled
to false. By default lazy loading is enabled which can be a bit confusing since older versions of EF didn't even support lazy loading.
Disabling lazy loading "activates" explicit loading and unsurprisingly requires you to explicitly load related objects. In your case you can do this by either using the Include
method (this is called eager loading):
var query = from a in _contextProvider.Context.Addresses.Include("State")
where a.CityName.StartsWith("I")
select a;
or access the related property in query (which modifies the final query):
var states = (from a in Addresses() // Addresses is your query method
select a.State).ToList();
In the second version linq-to-entities automatically includes the states because you are accessing them in the query. Note that your Addresses
method returns an IQueryable
and therefore the query will not be executed before you actually enumerate it. So the executed SQL query very much depends on how you use the query returned by Addresses
.
If you first execute the Addresses
query and access the states later linq-to-entities will not include them:
var states = (from a in Addresses().ToList() // <- ToList() executes the query before states are accessed
select a.State).ToList();
Lazy loading is often turned off to avoid unneeded roundtrips to the database. If you enable lazy loading and then immediately execute the query returned by Addresses
each access to a related object will actually produce a database query. But again: if you include the states in the final query linq-to-entities will automatically include them by generating a JOIN (no matter if you use lazy loading or not).
So your solution to use Include
to eagerly load related states (even if you don't access them later) is ok. And your original idea to use a join is also ok. But since you want your method to return an IQueryable<Address>
you have to do it on the call site (as described above).
From my experience enabling lazy loading often makes things a lot easier. If you don't know exactly what's going on it can result in a lot of unnecessary roundtrips to the database. But you can still use Include
to optimize your queries. To better understand how LINQ queries get translated into SQL statements I recommend to use SQL Profiler (or a free tool like Express Profiler if you use SQL Server Express).
On the other hand using explicit loading can also be a pain. Being forced to include all related tables can result in huge datasets. If for some reasons you can not include all related tables you have to explicitly check if an entity is loaded: context.Entry(address).Reference(a => a.State).IsLoaded
. If a nullable property is null you don't know if it is NULL in the database or just not yet loaded.