Entity framework. Reloading local data - c#

I have a control in WPF app that binds to this property
public ObservableCollection<Entity.Account> Accounts
{
get
{
_context.Accounts.Load();
return _context.Accounts.Local;
}
}
I expected that every time control reaches for data, local collection gets reloaded from scratch from database because of Load() method, but apparently I was wrong.
So I have two questions: what exactly Load() does if it's not loading entities from context to local? And how can i populate local collection by other means but Load()?
More details:
First here's how it's bound:<TextBox Text="{Binding Name}"/>
and in code-behind DataContext = _viewmodel.Accounts;
This Accounts property is exactly the one I wrote above. And the Name propery it binds to is a part of Account entity.
If you edit the account's name and won't call EntityContext.SaveChanges() it will change in local collection but won't change in database and calling Load() method won't refresh local collection. It only refreshes when program restarts (when context is created anew)

what exactly Load() does if it's not loading entities from context to local?
The Load is an extension method on IQueryable that enumerates the results of the query. This is equivalent to calling ToList without actually creating the list.
read here from MSDN
how can i populate local collection by other means but Load()?
Do you mean refresh? if yes then you can use the Reload
which will reload the entity from the database overwriting any property values with values from the database.
as:
foreach (var entity in _context.ChangeTracker.Entries())
{
entity.Reload();
}
Reload Method MSDN

Related

Custom Code on Entity Lazy Load

I've written a WPF desktop application, making use of Entity Framework to persist data (code first). I've got lazy loading enabled, which is working great.
For some of my entities, I need to implement some code every time it is instantiated through lazy loading. For example, I save some of my Datatables as lists in the database, and would like to convert these lists back to Datatables whenever the entity is lazy loaded.
I don't want to go through this conversion for the whole project necessarily (as not only can this be somewhat expensive, but for some projects the total objects can exceed available RAM). I also have all the 'custom' code that I'd like to run contained in one method. Lazy loading is therefore perfect, I just need to be able to run some custom code every time an entity is loaded.
So my question: is there any event (or other structure/pattern) that I can utilise or subscribe to so that I can run custom code every time an entity is initialised through lazy loading? I cannot use the parameterless constructor of said entity, as the properties haven't been loaded at that stage.
Thanks to the comments, I've implemented the necessary code in the appropriate get and set accessors. All properties are therefore being 'lazy loaded', which is in line with my requirements. My datatables therefore look as follows:
[NotMapped]
public DataTable MyTable
{
get
{
//Deserialize MyTable from byte[] or string property, obtained from database.
}
set
{
//Serialize MyTable to a byte[] or string property, which is saved to database.
}
}

DbSet: missing added item

In a DbSet entity collection of Entity Framework (6.1.3), when I add a new item, it is not returned from the collection afterwards. This is strange and unexpected. Here's some gathered sample code:
dbContext.Entities.ToArray();
// contains 3 entries
dbContext.Entities.Add(new Entity());
dbContext.Entities.ToArray();
// still contains 3 entries
How can this be? When I query dbContext.Entities in the immediate window in Visual Studio, it says something like "Local: Count = 4". Why does it hide the new item from me?
Update: If this collection doesn't do the obvious thing – returning what was added before – what do I need to do instead? It must return all records from the database when called first, and it must also include all changes (add and remove) when called later. SaveChanges is only called when the user has finished editing things. The collection is needed before that! SaveChanges might also be called somewhere in between when the user is finished editing, but the code might return and the view be displayed again at a later time.
A DbSet has a property Local. This is an ObservableCollection that contains all elements. The DbSet object itself represents just the query to the database.
From the documentation of the Local property:
Gets an ObservableCollection that represents a local view of all
Added, Unchanged, and Modified entities in this set. This local view
will stay in sync as entities are added or removed from the context.
Likewise, entities added to or removed from the local view will
automatically be added to or removed from the context.
So if you want to access the elements, always use the Local property to do it.
After adding new entity, you have to Save the change using dbContext object,Use
dbContext.SaveChanges(); or dbContext.EntityState.Added
You have to save the changes. Try
dbContext.State = EntityState.Added;
dbContext.SaveChanges();
you can use following code to get all the items,
foreach (var track in dbContext.ChangeTracker.Entries())
{
if (track.State == EntityState.Deleted)
Entity s = (Entity)track.OriginalValues.ToObject();
else
Entity s = (Entity)track.CurrentValues.ToObject();
}

Which asp.net control could be used for binding one EF object?

When I want to get more rows from MainTable, I'm using GridView with property SelectMethod so I can access data from every table that is connected to MainTable with FK like (inside gridview)
<asp:Label ID="masRegionNameLbl" runat="server" Text='<%#:Item.Region.RegionName %>'></asp:Label>
Here I can access column RegionName that is part of table Region that is connected with MainTable using navigation (FK RegionId in MainTable).
What I want now is to let every record have own detail page, where I can show more detailed info about chosen record.
My question is if there is any control in asp.net where I could bind one single EF object and access data similarly like in GridView.
First option was that GridView that showed me just one record, but it is not best for design. The second time I have tryed to load desired instance of MainTable in codebehind, but I in this case I can access only fields that are physically in MainTable, ex. I can access MainTable.Name but I can't access MainTable.Region.RegionName. When I try to access this field it gives me following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I wonder if I could have some control where I just bind one object - MainTable with some method and in this control I could do some html css design and access (view,edit) all data related to specific record that are constantly binded. Or is there at least something better than GridView for this case?
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
This error means that you are trying to access the context after it has been disposed (as the error states quite clearly :)) EF uses lazy loading for navigation properties. So what is happning is that you are accessing a navigation property and EF needs to get the data from the context, but the context does not exist any more.
There are two options:
You need to recreate the context or not dispose of it to begin with
before you make this call.
You can tell EF to load this navigation property eagerly, instead of lazily.
You can accomplish 2 by using the Include() method, which instructs EF to load the chosen navigation property eagerly. Look here for more information.
EDIT: If you would like to turn lazy loading off, you can do it per-property by not marking the navigation property as virtual or at the context level by adding this code to the constructor:
public class MyContext : DbContext
{
public MyContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}

Notifying Entity Framework context about changes at later time rather then at object's properties change

I have simple ObjectListView which displays some columns from EntityFramework of objects called Person (to simplify things). I load it with Entity Framework to ObjectListviewand then deatch it from Context. The person has multiple fields (like Name, Surname, File, ...).
Considering that some files are 5mb-50mb I don't want to load/save them to database without need. Now when someone double clicks in ObjectListView the selected Person is loaded into TextBox fields. When editing any of the fields I check if Person Name or SurName changed and if it did I updated the context like in the code below.
private void test (Person person){
using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
context.Persons.Attach(dokument);
if (person.Name != nameTextBox.Text) {
person.Name = nameTextBox.Text;
context.ObjectStateManager.GetObjectStateEntry(person).SetModifiedProperty("Name");
}
if (person.SurName != surNameTextBox.Text) {
person.SurName = surNameTextBox.Text;
context.ObjectStateManager.GetObjectStateEntry(person).SetModifiedProperty("SurName");
}
context.SaveChanges();
}
}
This works.. but what I would like to do is actually not save the changes straight away after users changes it but in the end when he presses BIG button SAVE ALL so then it would go thru all ObjectListView items and update them as needed in database. The problem is I can't update context and do it later since the Context wouldn't be used then but in the end when saving everything.
So what are my options? I was pointed to use INotifyPropertyChanged but as much as I looked at the code I don't think it's good for this type of situation or I simply don't know how to use it.
The other option was to actually create bool value per each Column from the database like
public partial class Person
{
public bool NameChanged {get;set; }
public bool SurnameChanged { get; set; }
}
And when saving I would be checking if bool changed and if yes do the ObjectStateManager magic on the context prior to save.
Any other way to do this?
I would advise to use a DataSource object in your xaml, and set your list view's data source to be bound to the DataSource object. Also use a pager, (You can get one from here:http://cid-51b2fdd068799d15.office.live.com/self.aspx/.Public/Samples%5E_2010/20100929%5E_DataPagerForWPF.zip) whose data source will also be bound to the DataSource object. That wold achieve 2 things:
The pager will query the data source object ensuring that it loads only x number of data elements (entities) at a time. Do not, however be fooled that if you have 5000000 entities, your data context will eventually store all of these entities in memory after the user has gone to the last page. These entities do get garbage collected.
The data source object contains a global instance of the context which will never go out of scope until the control or window is destroyed and garbage collected.
That being said here are two tips to make your life easier:
Entities by default implement INotifyPropertyChanged.
I do believe that as long as the context exists in the same memory space as the entities being modified, all you need to do is call SaveChanges() on the context to commit the changes to all modified entities. YOU DON'T HAVE TO DETACH the entities so that you can display them, modify them (well your user modifies them), then re-attach the entities to the context, and finally notify the context that the entity has changed.
Is using change tracking POCO entities an option for you?
http://msdn.microsoft.com/en-us/library/dd456848.aspx

How do I cache look up data in Linq to Sql, and use that data in a separate DataContext?

The project I'm working on has quite a lot of "look up" data associated with it. For this reason, on the first instantiation of the class that handles this, I set static IEnumerable's with all the lookup data, thusly:
private static IEnumerable<Kiosk> _kiosks;
private static IEnumerable<Paper> _papers;
private static IEnumerable<NewsAgent> _newsAgents;
And..
if (_kiosks == null)
_kiosks = db.Kiosks.Where(k => k.Active).OrderBy(k => k.Order).ToList();
if (_papers == null)
_papers = db.Papers.Where(p => p.Active).OrderBy(p => p.Name).ToList();
if (_newsAgents == null)
_newsAgents = db.NewsAgents.Where(n => n.Active).OrderBy(n => n.Order).ToList();
Each time this class is instantiated, I create new Linq entities for the data classes I need to save, using a brand new DataContext. When I try to submit these changes I get the following error:
"System.NotSupportedException: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported."
I gather that the cached lookup data, being created on a separate DataContext, is causing this issue. I would think that it should not matter, as the cached data is persisted with ToList, though at a guess each entity internally saves which DataContext it was generated on.
Having a static DataContext is out of the question, as changes to the data entities in the previous run may not be Submitted. Calling Submit on the datacontext on the second run causes an error where the original entites were not persisted.
How then, can I persist this cached data to be used on a new DataContext?
My assumption is that the cached lookup data has come from a separate
Don't cache the actual objects returned from the data context in the first place. Cache simple poco objects instead that have the bare minimum information on them, then use the ID values rather than objects when updating:
Employee.Status = cachedStatus;
becomes
Employee.StatusID = cachedStatus.ID;

Categories