I save an item to the database, which in turn causes a side-effect which effects a collection I've already obtained from the ObjectContext.
I simply want the collection to be refreshed. (Kind of like doing ObjectContext.Refresh -- but for a collection of items). Iterating over the collection is not an option -- there may have been items added or removed in the database.
How can I accomplish this?
In such case you must execute query to populate the collection again. Moreover you must correctly configure its MergeOption.
context.Things.MergeOption = MergeOption.OverwriteChagnes;
var myThings = context.Things.Where(t => t.IsFat);
EF and other ORMs don't like side effects in database.
Related
When a user hits the button, I'm executing the following code.
using (Context context = new Context())
{
foreach (Thing thing ViewModel.Things)
context.Things.AddOrUpdate(thing);
context.SaveChanges();
}
The updates are executed except for when the user selected a row and hit delete button. Visually, that post is gone but it's not really being removed from the database because it's not in the view model anymore. Hence, the loppification only ticks for the remaining things and not touching the removees.
I can think of two ways to handle that. One really bad - to remove everything from the context, save it and then recreate based on the view model. It's an idiotic solution so I'm only mentioning it for the reference's sake.
The other is to store each removed post in an array. Then, when the user invokes the code above, I could additionally perform the deletion of the elements in that array. This solution requires me to build the logic for that and I'm having this sense that it should be done automagically for me, if I ask nicely.
Am I right in my expectation and if so, how should I do it? If not, is there a smarter way to achieve my goal than creating this kill squad array?
At the moment, I do a double loop, first adding and updating what's left in the data grid. Then, removing anything that isn't found there. It's going to be painful if the number of elements grows. Also, for some reason I couldn't use Where because I need to rely on Contains and EF didn't let me do that. Not sure why.
using (Context context = new Context())
{
foreach (Thing thing in ViewModel.Things)
context.Things.AddOrUpdate(driver);
foreach (Thing thing in context.Things)
if (!ViewModel.Things.Contains(thing))
context.Things.Remove(thing);
context.SaveChanges();
}
The first thing I want to advice you is you should use the AddOrUpdate extension method only for seeding migrations. The job of AddOrUpdate is to ensure that you don’t create duplicates when you seed data during development.
The best way to achieve what you need you can find it in this link.
First in your ViewModel class you should have an ObservableCollection property of type Thing:
public ObservableCollection<Thing> Things {get;set;}
Then in the ViewModel's constructor (or in another place), you should set the Things property this way:
context.Things.Load();
Things = context.Things.Local;
From the quoted link:
Load is a new extension method on IQueryable that will cause the
results of the query to be iterated, in EF this equates to
materializing the results as objects and adding them to the DbContext
in the Unchanged state
The Local property will give you an ObservableCollection<TEntity> that
contains all Unchanged, Modified and Added objects that are currently
tracked by the DbContext for the given DbSet. As new objects enter the
DbSet (through queries, DbSet.Add/Attach, etc.) they will appear in
the ObservableCollection. When an object is deleted from the DbSet it
will also be removed from the ObservableCollection. Adding or Removing
from the ObservableCollection will also perform the corresponding
Add/Remove on the DbSet. Because WPF natively supports binding to an
ObservableCollection there is no additional code required to have two
way data binding with full support for WPF sorting, filtering etc.
Now to save changes, the only you need to do is create a command in your ViewModel class that call SaveThingsChanges method:
private void SaveThingsChanges()
{
context.SaveChanges();
}
I am writing a small game engine for XNA. Right now my entity manager has a list of all entities it can update and render. Lets say, however, that I want to split this list up into 'sub lists'. Maybe some entities do not require rendering, and so we would like to separate the rendering entities from the non-rendering entities, while maintaining another list which shows ALL entities for updating. So thats 3 lists.
Is there a way to maintain consistency between lists easily? To ensure that the exact same objects are being referenced in both lists? (Not a copy of the object?). In C++ we'd just have an array of pointers to entities that render, and another for entities that dont.
The problem isn't really putting entities into these lists, its disposing them thats throwing me off. To destroy an entity, i simply set a 'dispose' bool to true in that entity. The entity manger, when looping through all entities, removes the reference to that entity if 'dispose' is set to true, and the garbage cleaner destroys the entity because there is no more references left to it. Would i have to manually go through each and every list that has something to do with Entities and remove that entity from those lists to keep things consistent?
another example of this 'problem' is with quad trees. I have a 2d game and i generate a quad tree for all the entities. The entities that lie in between 2 grid locations are in 2 branches of the tree. how would i remove it from the tree? search the entire tree for references to that entity? seems a little pointless to have a quad tree if thats the case..!
Consider instead of 3 lists, have one list and 2 queries of that list.
var list = GetYourMainList();
var renderableEntities = list.Where(item => item.IsRenderable);
var nonrenderableEntities = list.Where(item => !item.IsRenderable);
// work with the queries
foreach (var item in renderableEntities)
{
// do whatever
}
Here, you can iterate over each query, the results will stream from the main list, and any update to that list will be reflected in the query results as they are iterated. The caveat is that the list cannot be modified (as in added to or deleted from) while the queries are being iterated.
As for your disposing problem, you could implement IDisposable. For your lists, you could make a class that contains the two lists, and if you need the entire list, implement an enumerator that would enumerate over the two lists.
You could put a wrapper around your entity that knows what lists it is in so that when you want to remove it, you can remove it from all places at once relatively easily.
If you have items in multiple lists, then yes, if you want to remove them you must remove them from all lists in which they occur. A simple way to do this is to assign responsibility for removing items to the items themselves: for example, rendering items would remove themselves from the rendering items list when you call RemoveFromLists() on them.
The use of queries as described by Anthony Pegram eliminates this complexity but is inefficient if the lists are large, since they cannot be incrementally updated.
As for quadtrees, a straightforward thing to do is to have each item keep a list of quadtree nodes in which it occurs (or if you don't want to add a field to your items, use a Dictionary). It is then simple to remove them from all nodes in which they occur in constant time.
You could have your entity expose a "Disposing" event that is fired before it is disposed. Then you could have your list's Add method register an event handler with the entity being added that will remove the entity from the list before it is disposed.
So I have the following code:
// Get the current user
_currentUser = WindowsIdentity.GetCurrent();
// Get the list of address for the current user
_dataMap = new DataMapDataContext();
_addresses = _dataMap.Addresses
.Where(address => address.InsertUserName == _currentUser.Name).ToList();
....
_addresses.Add(form.Item);
_dataMap.SubmitChanges();
When I call SubmitChanges nothing is saved in the database. Why is that? Am I missing the point? I thought with linq to sql you could just add items to your query results and then call SubmitChanges and it will work.... Clearly I am missing something.
Does it now work if you use "ToList"? If not then how do you insert stuff into the collection? (I don't think Add is part of IQueryable.)
Dont use _addresses.Add
You can't add directly to an IQueryable, you need to add it to the entity set.
Try this:
_dataMap.Addresses.InsertOnSubmit(form.Item);
_dataMap.SubmitChanges();
Of course, i can't see what form.Item is, but be aware it needs to be of the same Entity type as the _dataMap.Addresses entity set.
It makes no difference if you use .ToList().
With LINQ-SQL (unless you're using some sort of POCO mapping), you can't add items to a collection/query, you need to add the item directly into the Entity Set for the specified Data Context.
You can call .InsertOnSubmit as many times as you like, and .SubmitChanges will push all those INSERT's to the DB for you.
More info on InsertOnSubmit here.
when a new entity in my database is created and then i request a table from the datacontext the new entity does not appear.
is linq caching the table and returning the cached version? if so how do i stop linq from doing this.
DALConnector.Dc.Order.InsertOnSubmit(NewOrder);
DALConnector.Dc.SubmitChanges();
now i click a button that shows a form with a gridview on it databound to DALConnector.Dc.Order which doesn't show the new order
How are you rebinding the grid? It does not cache the result, so I am not sure why that is an issue. You have to requery the context to get the new record... Or, if you are rebinding an object's records (like you are binding customers), you could get away with ensurihg the order is added to the Orders collection in the customer object, and not having to requery.
So if you are binding in this way:
grid.DataSource = customer.Orders;
You would only get the new order back if you did:
customer.Orders.Add(newOrder);
dc.Orders.InsertOnSubmit(newOrder);
dc.SubmitChanges();
And then, you could bind customer.Orders directly.
The Linq2Sql DataContext does not cache the complete Table, it only has a cache of the retrieved entities for change tracking purposes. If you would use a new DataContext for querying after you have inserted the order, your result will probably be the same.
AS you are using Linq2Sql, which can only be used with SQL Server, I recommend firing up the SQL Server Profiler and check if a real insert statement is submitted to the database in the first place.
Check your dbml, are you using runtime insert or a stored procedure for Order?
Also check if you're not swallowing any Exceptions the DataContext may raise on SubmitChanges().
If this does not help, please add your query code so we can verify it also.
I would like to discard all changes made to linq tables (this means -- I use linq, and data are changed on client side, the data on server are intact). How to do this?
EDIT: problem partially solved
http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext/
It works as long as you don't use transaction. When you do and you use mixed "mode" for a record, there is a problem:
begin trans
insert a record
update inserted record
commit trans
When you update record as above Linq counts it as updated record, and in case of exception you have two actions -- transaction is rolled back and data on Linq side are discarded. On discard changes Linq tries to fetch it from the database (discard for update means refetching data for a record), but since all changes were rolled back, there is no records for update.
The question
How to improve DiscardChanges method in a smart general way to work with transactions. Or how to change the workflow of transactions/discard-submitchanges to make all those work together?
Those are not smart solutions:
refetching all data
recreating connection to DB (because it leads to (1))
To add to what Johannes said, I think the confusion here stems from thinking of the DataContext as something similar to a DataSet. It isn't.
A "table" in a DataContext is like a hint on how to retrieve a specific type of data entity from the database. Unlike a DataSet, the DataContext does not actually "contain" data, it simply tracks the discrete entities you've pulled out of it. If the DataContext disappears (is disposed), the entities are still valid, they are simply detached. This is different from a DataSet where the individual DataTables and DataRows are essentially bound to their containers and cannot outlive them.
In order to use the Refresh method of a DataContext, you need to use it on an actual entity or collection of entities. You can't "Refresh" a Table<T> because it's not actually a physical table, it's just a kind of reference.
Changes to entities connected to a DataContext are only persisted when you call the SubmitChanges method. If you dispose of the DataContext, there is absolutely no way that the changes can persist unless you manually reattach the detached entities to a new DataContext.
Simply discard the current DataContext without calling SubmitChanges() and get a new one.
Example:
DataContext myOldDc = new DataContext();