0

I'm building a Mobile MVC application and stumbled across many problems but this is bugging me a lot.

This is a Message class i'm reffering to:

    public class Message
{
    public int MessageID { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime Recieved { get; set; }

    [ForeignKey("User")]
    public int AuthorUserID { get; set; }

    //P\\ Navigation properties
    public virtual ICollection<MessageRecipient> MessageRecipients { get; set; }
    public virtual User User { get; set; }
}

I create the new Message object and save it in database.

            messageService.AddMessage(newMessage);
            Message freshMessage = messageService.GetNewestMessage();

At this point it has no Recipients attached. User Gets redirected to a View where (s)he can add recipients to a message.

Whe the user add the recipient i invoke the method through ajax that creates the MessageRecipient object and adds it to the Recipients collection of the message.

message.MessageRecipients.Add(recipient);

The ideal situation would be: when the user finished adding recipients and goes back to the Edit View, added recipients are visible.

When Edit action is being invoked the GetMessage method is invoked

Message message = messageService.GetMessage(id);

Because this message has been retrieved before it would be held in ObjectContext, so EF would serve me the entity from the memory rather than query DB for fresh one and this is what i want to happen. I do not know how to save the changes in that ObjectContext without saving changes to Db by invoking SaveChanges().

So my question is: Is there a way to change the state of the entity held in a memory so next time when it's been queried for i get the entity with the changes i have made to it?

I just want to work with the object and save it to Db when i've done with it rather than make a trip to Db each time user adds a recipient to a message.

I'm new to .NET and EF...

Any help would be appreciated.

Pawel
  • 2,566
  • 1
  • 16
  • 14

1 Answers1

0

Because this message has been retrieved before it would be held in ObjectContext, so EF would serve me the entity from the memory rather than query DB for fresh one.

No it will not be held in the context unless you are sharing context among requests. You should use a new context for every request (even every Ajax request). There are multiple reasons why you should not share the context. Count one additional - leaking context equals leaking memory.

So my question is: Is there a way to change the state of the entity held in a memory so next time when it's been queried for i get the entity with the changes i have made to it?

Yes there is a way but it has nothing to do with EF. You must held your detached Message in session or in other store making your application workflow statefull and persist the message to database using EF only when the whole editing is complete.

Community
  • 1
  • 1
Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
  • Thanks for that :) I should probably rework a lot of my code now. I tried to make using statements for each of my methods within repository but i was not able to make use of lazy loaden properties anymore. What would be recommended place to store the object? Is session the first thing i should look at? – Pawel Mar 14 '12 at 15:50
  • If you need to store context somewhere use `HttpContext.Items` but even that you should dispose your context at the end of your request processing. – Ladislav Mrnka Mar 14 '12 at 15:52
  • Could you please point me into right direction with using the new context for every request and be able to uzy lazy loading, or other method of accessing related entities after the context been disposed, please? – Pawel Mar 14 '12 at 16:14
  • You cannot use lazy loading after the context is disposed. Moreover using lazy loading in web application is needed only in rare scenarios because in each request you in most cases know what data you will need upfront so you can use eager loading. – Ladislav Mrnka Mar 14 '12 at 16:32
  • with lazy loading i can do this: `var messages = (from m in entity.Messages from mr in entity.MessageRecipients where m.MessageID == mr.MessageID && mr.UserID == userID select m);` and without marking navigation properties i get this **Method'System.Data.Entity.Infrastructure.DbQuery`1[IMS.Models.Entities.MessageRecipient] Include(System.String)' declared on type 'System.Data.Entity.Infrastructure.DbQuery`1[IMS.Models.Entities.MessageRecipient]' cannot be called with instance of type'System.Data.Objects.ObjectQuery`1[IMS.Models.Entities.MessageRecipient]'** when... – Pawel Mar 14 '12 at 16:48
  • doing this: `var messages = (from m in entity.Messages.Include("MessageRecipients").Include("User") from mr in entity.MessageRecipients.Include("User") where m.MessageID == mr.MessageID && mr.UserID == userID select m);` @Ladislav Mrnka – Pawel Mar 14 '12 at 17:21