ASP.NET C# EF - How to benefit the full object aft

2019-08-06 02:03发布

问题:

I've been working on ASP.NET C# with Entity Framework and some people help me very much on certain key points.

There also one point I could not understand fully. Aren't we supposed to use the object and its subobjects (foreign key relation table data) when we retrieve the data from EF?

Here is my database design (which was also displayed in my previously answered question)

In my code, I simply get Member entity like this:

//In some aspx.cs file
var Mem = new MemberManager().GetById(2);

//In MemberManager class
public Member GetById(long id)
        {
            using(var Context = new NoxonEntities())
            {
                return Context.Member.First(c => c.Id == id);
            }
        }

When I do this:

var Mem = new MemberManager().GetById(2);
var Lang = Mem.Language;
//I get 
//Error: 'Mem.Language' threw an exception of type 'System.ObjectDisposedException'

In order to get rid of this exception I needed to do this:

public Member GetById(long id)
        {
            using(var Context = new NoxonEntities())
            {
                var Result = Context.Member.First(c => c.Id == id);
                //Getting the Language Entity
                Result.Language = Context.Language.First(c => c.Id == Result.LanguageId);

                return Result;
            }
        }

Do I have to run a SELECT in order to have FULL entity? What if there were ANOTHER related table to Language table lets say Feature Table. Should I do this:

public Member GetById(long id)
            {
                using(var Context = new NoxonEntities())
                {
                    var Result = Context.Member.First(c => c.Id == id);
                    //Getting the Language Entity
                    Result.Language = Context.Language.First(c => c.Id == Result.LanguageId);
                    Result.Language.Feature = Context.Language.Feature.First(c => c.Id == Result.FeatureId);
                    return Result;
                }
            }

Which could go verrry long and I'm pretty sure (at least I genuinely hope) I am wrong about something, but if we cannot use the object and its subobjects AFTER selecting, what is the purpose of having EF? Can we only use the subobjects in site the using(var Context = new NoxonEntities()) block?

Thank you,

回答1:

Think of the context as a database connection. You make this connection available to you when you create the context in the using statement and throw it away at the end of the using. Everything after the using block cannot access the database connection anymore. You get an exception here...

var Lang = Mem.Language;

...because lazy loading tries to load the Language navigation property from the database, but the connection to the database is already disposed. You can use such a lazy loading only within your using block when the connection to the database is still available.

You can simplify loading the navigation properties in your example by using eager loading with Include:

public Member GetById(long id)
{
    using(var Context = new NoxonEntities())
    {
        return Context.Member.Include("Language").First(c => c.Id == id);
    }
}

Or for both navigation properties use:

return Context.Member.Include("Language.Feature").First(c => c.Id == id);

It will load the member and the language and feature in one single database query.



回答2:

Your problem is due to Lazy Loading. What's happening is that EF isn't loading your related entity Language because it's not sure it's going to need the data. Then, you're disposing the context so when you attempt to access the Language navigation property it's unable to make the jump.

You have a few options here. You can eager load, here's a great blog post on eager loading, the Language entity:

var Result = Context.Member.Include("Language").First(c => c.Id == id);

Or, you need to keep the context alive throughout the entire request. Here's a good post on a great method to keeping your context alive for each request.

I do remember you're other post though - and I believe you're detaching your entity and storing it somewhere else, then re attaching. If this is related to that functionality, then accessing your Language object, after you re attach it to a context will also fix your problem.