I’ve done this demo many times in conference and user group sessions. Someone on the ADO.NET forums asked how to do it and I thought I would just do a quick tutorial with screenshots.
What this Tutorial does is demonstrate how to create and use a data source from a particular entity in the model. I’m just doing simple drag and drop and no filtering or anything here with the goal of just a quick basic walkthrough for getting started.
Start by creating a Windows Application.
Add an Entity Data Model.
Select Data from the menu and choose Add New Data Source
In the first page of the wizard, choose Object as your Data Source Type.
The next screen of the wizard will show the namespaces in the current solution. Open up the namespace for the application
then choose the entity which you want to use as a Data Source. I will pick customer.
Then you can Finish the Wizard.
Now to get easy access to the datasource, go back to the menu and choose Show Data Sources from the Data menu.
The DataSources Window will be placed in your IDE in it’s default location. Mine docks with the windows on the left.
When it’s not pinned it gets tucked away with the others. You can undock it and put it wherever you want.
I can now drag and drop the customer data source onto the windows form to get the automatic DataGridView and Navigation toolbar (this is normal behavior for DataSource and not specific to Entity Framework).
There are a few more steps to actually getting user interaction with this. You need to populate the Binding Source and if you want to edit, you’ll need to add a little code to the save button on the toolbar.
You’ll need to enable the BindingNavigatorSaveButton (just click the save icon on the navigator toolbar and change it’s Enabled property to True). Additionally, you’ll probably want to format the grid which you can do easily from it’s SmartTag and more thoroughly through the properties window.
Here’s what the code behind looks like in my form enabling me to view, add, delete, edit and save data.
Imports WindowsApplication1.AdventureWorksLTModel Public Class Form1 Private aw As AdventureWorksLTEntities Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load aw = New AdventureWorksLTEntities CustomerBindingSource.DataSource = aw.Customer.OrderBy(Function(cust) cust.CompanyName) End Sub Private Sub CustomerBindingNavigatorSaveItem_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles CustomerBindingNavigatorSaveItem.Click aw.SaveChanges() End Sub End Class
Note that because the AdventureWorks Customer table has the following constraints: ModifiedDate must be a valid date value and the PasswordHash and PasswordSalt fields cannot be Null, I have extended the entity class to take care of these things when SaveChanges is called.
Sign up for my newsletter so you don't miss my conference & Pluralsight course announcements!
Hey Now Julie,I really enjoy your blog & this post was very simple yet informative. Thx 4 the info,Catto
Hi Julie,I’ve really benefited from your entity framework blogs here as well as your posts on the msdn forums. In this post, I noticed that you declared AdventureWorksLTEntities as a class member. I couldn’t find any full documentation on the ObjectContext class (I assume this is because its still in Beta), but for the DataContext which is the equivalent in LINQ to SQL, Microsoft states:"In general, a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations."Personally, your way appears to be more convenient as I cannot think of a way to do what you’ve done without declaring it as a member class, but do you know:1) If the above statement/suggestion from Microsoft applies to the ObjectContext class2) Any reasons for the above statement/suggestionThanks again for all of your work.Ean
Thanks Ean.You’ve made a good observation and a logical one. This is something that I had to be convinced to do myself at first. ObjectContext and DataContext are actually different in this light.The ObjectContext is there to manage the entities. Connecting to the database is a small part of it’s job. With clientapps, the ObjectContext was designed to hang around, so that even after getting the data from the db (and closing the db connection) it still needs to manage the entities (epecially for change tracking).Check out this post where I quoted Microsoft’s guidance on this:http://www.thedatafarm.com/blog/2007/12/21/SomeGreatEntityFrameworkGuidanceAboutPerformanceInClientApplications.aspxhthjulie
Thanks Julie. That was exactly what I wanted to hear since I wasn’t looking forward to trying to find an alternative. My question was actually related to a Winforms app. Next time I’ll try to be more specific as this situation shows how important that can be.
I guessed that you were talking about WinForm apps since that was the focus of the blog post! 😉 WinForm apps definitely falls under the umbrella of "client apps", although I could have been clearer and said "client side apps".
Hey Julie… sorry to put this comment in this ‘older’ post, but I didn’t find anything else that would reflect to my question.I was wondering how I could add ‘related’ fields in such a grid like you have in this example.Example: Customer has a link to Address, and it’s designed that he has only one address ( so the relational mapping points to 1 ). So how can I get the Address fields in the DataGrid ? ( the ObjectQuery is of the type Customer ).Any thoughts?Thanks, Glenn
GlennI would just format the columns manually in code and assign the properties to them there. That way you should be able to bind a column to CUstomer.Address.Street.julie
Well Julie…I do understand your solution, but I can’t see how to implement this.Because now at form load I’m using ObjectQuery<Customer>.ToList() to fill the BindingSource.Does this mean I somehow have to add the related data inside this BindingSource as seperate items ?So that the newly added columns can be ‘databound’ to this ?Or do I have to set all columns manually now ?Sorry for asking, I just don’t get the ‘hang of it’…
Hi Glenn,Ahh, I just opened up one of the samples from my book to see. I have created unbound columns in the grid and then in code in the grid’s RowPrePaint mehtod, I’m setting the values of those columns manually.But the binding source has to provide that information which means that if you can write your query to eager load the address data then you’ll have access to it when you populate the grid.Do you have a safari account or a subscription to the rough cuts version of my book? If so , look at chapter 7. 🙂
Ok… so it’s possible :), that is nice to know.But no I don’t have an account nor a subscription, BUT I am planning to buy your book as soon as it gets out 😉
Hey Julie… last note on my question ;)I figured it out! Thanks to your tip of the PrePaint event, I remembered a program I wrote some time ago where I had a column in a grid that contained icons based on some value in another column of the same grid. It also needed to ‘trap’ a grid event to set the correct column value.But in this example I’m using CellFormatting event of the grid instead of RowPrePaintHere is my little code I use now for the grid with Entity Framework data :From load :this.schoolBindingSource.DataSource = DataContainer.GetInstance().DataEntities.School.Include("Address").OrderBy(sch => sch.schoolName).ToList();And then :private void gridSchool_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e){if(!this.gridSchool.Rows[e.RowIndex].IsNewRow && this.gridSchool.Columns[e.ColumnIndex].Name.Equals("addressStreet", StringComparison.OrdinalIgnoreCase)){School currentSchool = this.gridSchool.Rows[e.RowIndex].DataBoundItem as School;e.Value = currentSchool.Address.addressStreet;}}Thanks again for the tip !
Excellent news!
I’ve got your new book and I’m working through an example much like you have done above to create a simple first pass OLTP win form to maintain employee’s information in my database.I’ve got that basically up and working where I query and edit and save just as you have done in this example.Now, I want my users to be able to "search" for an existing employee that is in the BindingSource and here I run into issues.The first most obvious way was to just use the "Find" on the BindingSource but when bound to a ObjectResult it is indicated as not searchable (or filterable, but that is another issue).So, the next most obvious way (to me anyway) was to get the ObjectResult from the BindingSource.Datasource and simple do a LINQ query against it to find the correct employee.Then I’d scrolled to it in the BindingNavigator.Dim test As ObjectResult(Of Employee) = CType(employeeBindingSource.DataSource, _ObjectResult(Of Employee))Dim foundEmployee = (From emp In test _ Where emp.windowsUserId = loggedInUser _ Select emp).FirstThe problem here is that an error is thrown that the ObjectResult can not be enumerated again.Now, I’ve tried every way that makes sense to me to add this simple functionality and I’m having no luck.Suggestions?Thanks,Stephen Study
StephenYeah – you need to search the datasource, not the bindingsource and as you have discovered (or may have already known) ObjectResult can only be enumarated once.Are you tied to using an ObjectResult? Can you push your query results out to a List instead?CustomerBindingSource.DataSource = aw.Customer.OrderBy(Function(cust) cust.CompanyName).ToListIf you do use the list instead, verify all of your change operations – edit, insert and delete – because in EF databinding there are a few surprising nuances when you don’t use the ObjectResult.Julie
Julie,Well I’ll switch it over to List(OF Employee) and see what happens.I had used the ObjectResult because I read in your book there could be issues with data binding which I see you also indicate again here.I’ll give it a shot!Thanks for the help,Stephen
I have the same problem than Stephen.What are these "issues" with the ToList<>() as a DataSource??With the ObjectResult<> as DataSource we can’t search, nor sort nor filter directly on the BindingSource?There is no walkthrough for this?Thanks.Mauricio.
Hi Mauricio,the problem that I discovered which was confirmed by the EF team is that there can be unexpected behavior when deleting child items that are bound to controls with databinding. e.g. if you have an order graph and you bind the order’s line items to a datagrid.I couldn’t remember exactly, so i just looked at my best resource, my book! 🙂 I am copying the following from page 178.ObjectResult is an enumerable collection that has special features to enhance data binding and the binding’s ability to interact with the ObjectContext. Although you may find that some updates and additions will work properly even if you returned a List(Of Customer), you may also get unexpected results. One bad result that you can count on is that when you delete an item, no delete command will be sent to the database. Withan ObjectResult, the delete will work as expected.
Thank you very much. Very informative article. I am working at Entity Framework these days. I have three entities i.e Category, Definition, Version
One Category can have many definitions and one definition can have many Versions. I want to retrive all latest version (Version.Number is maximum) by categoryId. How I can query it using Entity SQL please
Hi,
I want to show a Master Detail Grid in a WinForm.
The thing is I want to do it without drag and drop and without databinding controls, just code.
Is it posible? can you provide a sample code?
Thanks in advance.
Noel
Hey Julie, i hope you still read the post here cause i really have a weird problem..
As stated in your book, after i set the object Data Source to an Entity object and then drag some fields to the windows, i have i program stall issue.
For example i have 3 fields, name surname and jobs which is a combobox pointing at the jobs table, when i enter the name texbox or any other control, the program just wont let me leave that control. I cant interact with any of the controls including binding navigator..
Only way to get out of the stall is selecting another row from the datagrid which points at the entity object itself..Of course the same stall happens for the new row again..
Could you tell what might be causing this disturbing issue?
Hi Yosi
I’ve never heard of this or experienced it before. It sounds more like a winforms issue…not specific to EF. You might want to try a windows forums specific forum such as [http://social.msdn.microsoft.com/Forums/en/winformsdatacontrols/threads]
Feel free to post back here a link if you find a solution.
sorry not to be more helpful.
julie
Hi Julie,
I been making a migration on a project from DataSet to Entity Objects following the steps in this example. I stuck in a problem the Stephen Study cited: "BindingSource when bound to a ObjectResult it is indicated as not searchable or filterable".
BindingSource.Filter its not available…
There is some way to implement this?
If has, could u put me in the right direction? Will be a life savior.
Tnks
@Joao
There are lots of limitations when using an objectResult. Perhaps you should consider using an ObservableCollection which is commonly used with WPF.
julie
I have your Entity framework book, and I have a form with 2 grids in a 1 to many relation. The master grid has name and ID column. In the detail grid, it has the masterid along with the other coluns in the detail grid. I need to display a combobox for the master grid name in the detail grid(Instead of the ID, I want to display a dropdown with all the names in the master grid). How can we do that? Please let me know.
Hi
I was going through the videos and loading related data via entity framework. I was wondering if i can more insight for the following for example
Product and Product categories table.
I have product detail gridview on which I double click then it opens the product forms where I can edit all the details of product including changing the category of it. I want to display category by name in drop down, and when I change the category it shall update category id in Products table. I am fairly new to this, trying to learn it. I want to achieve this functionality in winforms.
Thanks