简体   繁体   中英

Entity Framework Entity not showing properties of related entities

I'm new to Entity Framework. I've created a Multi Tier Application, in MVC, using Ninject.
I have three tables in the database. Say Table A, Table B and Table C.

Table A has a foreign key relating it to Table B  
Table B has a foreign key relating it to Table C

Table A => Table B => Table C

My Application has a "service" which will be called from an MVC Controller.
The service acts as a repository for every entity (ie TableAService, TableBService), which is responsible for Creating, Reading, Updating or Deleting Entities from the EF DataContext, aswell as possibly performing business logic on those entities.

Within my MVC controller I have a reference to the appropriate service. For example:

private TableAService _tableAService;

public TableAController(EFDataContext dataContext)
{
    _tableAService = new TableAService(dataContext);
}

public ActionResult Index()
{
    return View();
}

TableAService would look something like this:

private EFDataContext _dataContext;

public TableAService(EFDataContext dataContext)
{
    _dataContext = dataContext;
}

public TableA GetById(int tableAId)
{
    _dataContext.TableA.SingleOrDefault(ta => ta.TableAId == tableAId);
}

I appreciate that the example's service would be tightly coupled to the dataSource, my actual implementation differs slightly but the concept is the same, I have a service with a dataContext that I'd like to return entities from.

QUESTION : - When I'm in the GetById method in the TableAService, SingleOrDefault gives me a TableB navigation property, which allows me to access all TableB's properties, including a TableC navigation property.

However, when I pass TableA back to the Controller, I can't access any of TableB's properties.

Within the Service I've also tried:

private ObjectSet<TableA> _objSet = _dataContext.CreateObjectSet<TableA>();

and

return _objSet.SingleOrDefault(ta => ta.TableAId == tableAId);

This doesn't seem to make any difference to being able to Access the TableC navigation property on TableB from the TableA entity.

Any help would be greatly appreciated!

Cheers,

James

The contents of a navigation property can only be loaded within the scope of an active ObjectContext.

This is required because the actual rows will be fetched through a round-trip to the database.
In your case your are trying to access a navigation property after the ObjectContext that was used to retrieve the entities in the first place has been disposed and the connection lost.

Assuming you're using Entity Framework 4 there are 2 solutions to this problem:

  • Eager loading: the related entities are loaded up front, that is you explicitly instruct Entity Framework to load all related entities while it's retrieving the results of the query.
    This can be done in a couple of different ways: by including the related entities in the query's projection, by invoking the ObjectQuery.Include method or by invoking the Load method on the navigation property, alternatively the ObjectContext.LoadProperty method.
  • Lazy loading: the related entities are loaded on-demand, that is when the navigation property's getter is accessed for the first time. Note that this must still be done within the scope of an ObjectContext.

In your case eager loading using the Include method is probably the most appropriate solution:

public TableA GetById(int tableAId)
{
    return _dataContext.TableA
        .Include("TableB.TableC") // use dot-notation to specify depth in the object graph
        .SingleOrDefault(ta => ta.TableAId == tableAId);
}

Related resources:

Try changing your GetById method to:

public TableA GetById(int tableAId)
{
    return _dataContext.TableA.Include("TableB").SingleOrDefault(ta => ta.TableAId == tableAId);
}

If you want to get the TableC record as well, use:

public TableA GetById(int tableAId)
{
    return _dataContext.TableA.Include("TableB.TableC").SingleOrDefault(ta => ta.TableAId == tableAId);
}

The reason is that Entity Framework uses "lazy loading", which means that stuff isn't loaded from the database until you really need it. The trouble is, once you're out of the service, the data context doesn't exist any more to get the table B record. The Include method instructs EF to load the data from related tables straight away.

It's took some digging, but the problem I was experiencing was that my application wasn't referencing System.Data.Entity.

Adding the reference to the application allowed me to access the properties of the related objects from within the controller.

Thanks for your answers guys, they did help me rule out possibilities. I up voted each.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM