I have a binding source who's datasource is the result from a linq query. I have several controls bound to this binding source. When the value of the controls is changed, how would I go about saving the value against the binding source and eventually the db?
Thanks
EDIT:
So my bindingSource is lined to a datasource like the following:
this.jobBindingSource.DataSource = jobDao.JobByJobNumber(jobNumber);
The query backed by the dao is:
return (from job in this.GetTable<Job>()
where job.Job_Number == jobNumber
select job).First();
LINQ queries usually return something that is readonly (if what the query returns still contains some context to the datasource this might be different - in that case there may be some way to commit changes made to an item)! You did not provide any details about what you are querying against, but this should also be the case for you.
Therefore you have to propagate changes to your data manually - manipulate the datasource you are querying against, at least changes can not be "written back up" through the LINQ query you bound the controls to.
Related
The question has been asked a lot (which I am aware of) however I have been unable to implement something which works for me specifically.
I am using Entity Framework in order to handle data interaction (and am somewhat new to the contept) with a WinForms application; this works fine and means that the DataSource of any DataGridView control is a list of objects.
The user is to have the ability to sort on multiple columns. For DataGridView controls which have no DataSource (as they're one-way and I have pulled the data straight from the DB) this is not an issue, as a custom IComparer class handles this sorting.
However, I appear to be unable to sort grids which have a DataSource where the DataSource is a set of objects by multiple columns.
The important thing to observe is that the DataSource of the DataGridView could be a list of objects of any type (Customers, Recipes, Cars etc.) as the grid could be representing data from any table in the database through objects.
The way I am getting the DataSource for the DataGridView control is as follows (this example is for the users in the system):
dtgUserList.pFormGrid.DataEntityProvider.USER_LIST
.Where(X => X.USER_ID > 1)
.Load();
dtgUserList.pFormGrid.DataSource = dtgUserList.pFormGrid.DataEntityProvider.USER_LIST.Local.ToBindingList();
When the DataSource of the DataGridView was a DataTable which was a direct database query, I could simply cast the DataSource of the DataGridView as a BindingSource and then set the Sort property to be the sorting string. For example, if sorting the user list by USER_NAME and then by PROFILE, the sort would be as follows:
((BindingSource)DataSource).Sort = SortArgs;
Where SortArgs = "USER_NAME ASC, PROFILE ASC". This could be determined simply by iterating through the columns which were sorted and extracting and concatenating the DataPropertyName of the column.
If I try and cast the DataSource of the DataGridView control which is bound to the above set of USER_LIST objects however, I get a compile time error indicating that the cast cannot be performed.
To try and address this, I am creating a new BindingSource from the existing DataSource in order to then try and apply the same sort logic (of just creating the sort string and then passing this to the Sort property of the BindingSource):
BindingSource GridBindingSource = new BindingSource(DataSource, null);
SortedGridBinding.Sort = SortArgs;
Unfortunately, when I do this, the SupportsAdvancedSorting property is always false, despite the BindingSource implementing IBindingListView, which is documented in the MSDN article for this property.
What I am primarily trying to understand is why this property is always being set to false, despite the class I am using implementing the required interface to allow multi-column sorting. I have also seen a number of examples on how to implement sorting of lists of objects by multiple properties, such as this example however, unless I am mis-understanding something, this still relies on a strongly typed IList input.
As an option you can add System.Linq.Dynamic reference to your project, then after using System.Linq.Dynamic namespace, you will be able to sort an IEnumerable<T> or IQueryable<T> by passing sort column and sort order as string, for example:
var list = db.Products.ToList();
bindingSource1.DataSource = list.OrderBy("Name ASC, Price DESC").ToList();
Resources
NuGet package for System.Linq.Dynamic. You can install the package simply using this command in package manager console: Install-Package System.Linq.Dynamic
GitHub repository for System.Linq.Dynamic
Scott Guthrie's blog post
about Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
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.
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 have written a page which uses Linq to query the database and bind the resulting IQueryable to a datagrid. I have a partial class which contains extra properties which derive their values based on other values brought in from the database.
Sorting works fine on fields that are actually in the database but not for the derived fields. When I attempt to sort on such a field I get an error saying "The member 'Trip.Difference' has no supported translation to SQL.
Any idea how to allow sorting on these derived fields?
The problem is that you are binding to an IQueryable, so every time you enumerate it, you are translating the LINQ expression on the IQueryable to a SQL statement and going back to the database to execute it.
If you are trying to sort on properties that are not bound to the database model then you will get the error mentioned, as those properties only exist once an object has been created from a data row.
The simplest solution is to call ToList() on the IQueryable before using it for sorting and data-binding, so that you sort on the in-memory objects where the properties are actually available. ToList() converts your IQueryable into an IEnumerable (via List<T>), and stops it from going to the database again via LINQ to SQL.
This is generally a good design pattern to follow - the last thing you want is consumers of your business layer being able to unwittingly execute arbitrary queries against your database, simply because you returned IQueryable where you should have returned IEnumerable.
Call ToEnumerable() first, and then add the OrderBy:
var q = (from a in mDataContext.Somethings()
select a).ToEnumerable().OrderBy...
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();