简体   繁体   中英

c# entity framework with virtual property query

I have this class:

    public class Message
    {
        public Message()
        {
            Contacts = new List<Contact>();
        }

        public Message(string Sub_Message, string Body_Message, string Date_Send_Message)
        {
            Contacts = new List<Contact>();

            Subject = Sub_Message;
            Body = Body_Message;
            Date = Date_Send_Message;
        }

        public int MessageId { get; set; }
        public string Subject { get; set; }

        public string Date { get; set; }

        public string Body { get; set; }

        public virtual IList<Contact> Contacts { get; set; }
    }

I want to get the table of the Contact, because of that Messages is virtual and all the lazy loading stuff,

This call didn't work to me and got this error:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. in Reference Table

syntax:

    public ObservableCollection<Model.Message> LoadMessages()
    {
      using (db) {
       var x = from qr in db.Messages
                            order by qr.Subject
                            select qr;
          }
     }

While this works:

public ObservableCollection<Model.Message> LoadMessages()
{
    using (db)
    {
        var Messages = db.Messages.Include(z => z.Contacts).ToList();

        return new ObservableCollection<Model.Message>(Messages); 
    }
}

So I am using the queries inside a service called MessageService, Everytime I want to use the dbContext I create a function for it and put it inside using(db)

Like this:

     public class MessageService
        {
            ReadingFromData db = new ReadingFromData();
            public ObservableCollection<Model.Message> LoadMessages()
            {
                using (db)
                {
                    //Do something with db
                }
            }
}

Also, can someone explain to me how this works, and how to work with entity framework queries correct

Thanks

First of all, you should understand that this code does not query database:

var x = from qr in db.Messages
        orderby qr.Subject
        select qr;

it's just a query definition (expression) which should be translated into SQL and sent to the database server when you'll execute it. Executing is enumerating query results, or using one of LINQ operators with immediate execution type (see Classification of Standard Query Operators by Manner of Execution ). Ie when later in the code you'll enumerate x or if you'll try to store query results in a list, it is possible that database context db will be already disposed. And of course, you will get an error

var x = db.Messages; // query is not executed
db.Dispose(); // context disposed
foreach(var m in x) // exception here, you try to execute query which uses disposed context
   ...

Now about lazy-loading. It works by storing database context in the proxy entities which inherit from your entities. So actually db.Messages will return entities of some type MessageWithDbContext with db value stored internally. It is required for making additional 'lazy' database queries later . And again, if at that point of time database context is disposed, then you'll get an exception:

 var x = db.Messages.ToList(); // query is executed, messages are loaded
 db.Dispose();  // context disposed
 foreach(var m in x)
    m.Contacts.Count(); // exception - you try to execute contacts query with disposed db

How to solve this issue? Either make sure that database context is not disposed while you are working with the query and making additional 'lazy' calls. Or use eager loading as you are doing in the second example. Eager loading allows you to load related entities when you are executing the query:

 // both messages and contacts are loaded from database when you execute the query
 var x = db.Message.Include(m => m.Contacts).ToList();
 db.Dispose();
 foreach(var m in x)
    m.Contacts.Count();

In this case no additional 'lazy' calls are required, so you can dispose database context and work with query results.

Lazy loading will work only if the property is accessed while the connection to the context is open (or not disposed).

            using (db)
            {
                //If you try to load the data here, lazy loading will work.
            }

Now, when you use include, EF does eager loading and gets the related data for you. That is why your data is available when you are using include.

var Messages = db.Messages.Include(z => z.Contacts).ToList(); 

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