I am experiencing with a class generator I've written, which generates a class for each table in database with each table field as a property and such.
Before that, I used to add a typed dataset to the project and add some tables to it. It automatically detected the relationship between tables and when I added a parent table as data source of a datagrid, I could add another datagrid and use the foreing key data member of it's bindingsource to fill it, and when someone moved the focus on parent datagrid, the data in child datagrid would change accordingly.
Now that I have my classes, I add an object as data source for my 2 datagrids, but obviously it doesn't detect a parent child relation. But It'd really help if I could have that foreign key relation in my object datasources.
Is there any way to have that relation in object datasource?
If you use LINQ ORM, your foreign key relationships are reflected automatically in your generated model.
Take a look at http://www.hookedonlinq.com/LINQtoSQL5MinuteOverview.ashx for more info.
In case you use ADO.Net, there might be a chance you forgot to tick the choice "Include Foreign Key Columns in the Model." in the ADO wizard but no worries (we've all been there, tick boxes are notoriously easy to overlook ;) ), you'll simply have to re-generate the model (re-run the wizard) but be sure to copy-paste any custom code you've added to a text file or something, so you don't lose it. Good luck!
Related
I'm trying to do linked parent-child datagridview controls in a Winforms app bound to SQL Server.
VS can generate working code if I model a few tables in the DataSet and define the Relations between them. However, my understanding is that the DataSet is loaded at startup in that case(using the generated code).
The next challenge is that I need a parent table as before, but the child table is bound to a Table Valued Function. It's not clear how to link the two controls. Presumably I need to call Fill on the child control on some row selection event change? In other words it's code that has to written on the control, not something that can be built in the gui automatically from the DataSet?
It's essentially a lazy-load scenario, where each selection in the parent reloads the data in the child.
When I try to insert or update data in my WPF usercontrol datagrid, the data is not being saved to the corresponding property. This is being caused by (at least so I believe) my bound property having the [NotMapped] attribute, all the other properties without the annotation are working correctly.
The data which need's to be updated is inside a DataGrid component which is bound to an ObservableCollection with the appropriate model. Inside the model there are several properties with the [NotMapped] annotation, these properties should be excluded in the creation of the table (model) in my database, though I do need them for binding input, hence the use of the [NotMapped] annotation.
Since the data is bound to a ObservableCollection I can't add the [NotMapped] properties to the usercontrol directly (so they wont be a part of the model).
Below an example:
Part of the XAML
In the image below we can see 1 property (pBreedte) which is 1 of the NotMapped properties, as well as the itemsource of the datagrid:
UserControl Code behind (part of it)
Part of the model which is used in the ObservableCollection
The model is being used for EF6 (code first).
Is there any way that the NotMapped property values can be stored / saved?
The easiest would be to just include the NotMapped properties in the database (so removing the annotation completely) but I am trying to avoid this.
More background information
The NotMapped values are added because they function as a placeholder property. Initially I had several decimal properties bound to the datagrid directly, but textboxes can't handle decimal values very well (WPF validation rule preventing decimal entry in textbox?). So I created a string placeholder for those decimal properties, when the form is being saved the decimal properties are being set to their string placeholder counterparts. This way the user can add decimal places without having to use a delay, value converter or anything.
If you don't need that information in your database, then don't store it - meaning your approach is good.
What I think here what might be the problem is that you are using your entity/database model as UI model.
I would suggest that you try to introduce a different model for the UI controls and user input. The models might seem to be duplicate at the beginning but while you are working on your application they will start to differ, but still describing the same items just form different perspectives.
Example:
Entity model has a class CarEntity. It is a pure POCO class, having only the needed properties that will contain the data in the corresponding table.
Ui model has a class CarUi. It has the same properties as the CarEntity. They are loaded and mapped from the database (from the CarEntity) shown to the user. If the user changes something, the diff values are mapped from the CarUi to the CarEntity and then stored to the DB.
With this separation of models approach, you should not face the issue where one constraint (mark column not to be stored in a table) influences other functionality.
Hope this helps,
Cheers and happy coding!
I have a question which seems too specific for google, or maybe I don't use the correct words; I find nothing about this.
I have severals tables and each of them contain several Entities (columns). Every tables has a Common Primary Key, we can use this column as a link for every table.
I want to pick some entities of a table, other entities of another table, other entities of another table, etc.. and send'em to a unique ObservableCollection, this ObservableCollection will be, in a second step, binded to a DataGrid.
I could create an ObservableCollection per table and then create a CompositeCollection of each ObservableCollection but I don't want to use the CompositeCollection, It doesn't display Datas as I want, I discovered this here(CompositeCollection binding on a DataGrid by MVVM)
How can I perform this? I have found lot of scripts but nothing about sending specific columns from specific tables on a unique ObservableCollection.
I hope I have been clear enough, If you want some code to illustrate, I can send what you want. But as it's a general question of a specific way to add datas on an ObservableCollection, I think it isn't necessary.
Thanks in advance!
EDIT1:
This is what my Database looks like:
(http://imagik.fr/view/123053)
I have the following data model:
Camp -> CampEvent <- Event.
Camp has CampId and Name associated with it.
Event has EventId, Name, Start/End (Dates).
CampEvent has (CampId,EventId)PK, CampId FK, EventId FK.
The tables are used to create a Domain Model and a Domain Service which is consumed from the client side on Silverlight.
I am successfully able to display the Event's table in Silverlight using a grid.
The Grid has two template columns - one to display a checkbox, and another to display the name of the event.
So now the problem is somehow I need to check the checkboxes when this control goes in edit mode.
I've noticed that the Grid doesn't have OnDataBound event, or it doesn't have a way of setting the state of each checkbox to checked other than through binding.
Well, apparently in Silverlight you don't have the luxury of messing around with the contents of a GridViewRow. You can, however, achieve this by changing the underlying data source.
In the above scenario we have a control which is used for creating an instance of Camp and associating it with one or many events. In a sense the control can either Create or Update a "Camp" object and its relationships with Events. The control state is controlled by an Enumeration public enum Mode { Create, Update }; and depending on which value this property has, the control will do either one, or both of the following binding binding operations:
Get all event data and display it in a grid composed of rows having a checkbox & label.
Check the boxes denoting the events in which a specific camp participates.
This was all nice and dandy in theory but in principle I realized Silverlight needs a discrete data source to bind to. I created a collection of a CampEvent custom object in which every element has a boolean prperty IsChecked, along with the event name and event Id. The CampEvent object is not a Domain Entity object and is only used for binding.
So to achieve my goal, these are the steps I took.
Declare ObservableCollection where T is used for only binding. In this case the underlying data source for T is our Event, and a Linq to Entity query was used to grab the Id and the Name of the Event and transforms it into a CampEvent object with its IsChecked property set to false by default.
If the Control is in Create mode I am done. The checkboxes in the Grid's template column are two-way bound to the IsChecked property of the underlying data source. Step one is enough to create the default UI with all check boxes unchecked. Otherwise go to 3
Well, number 2 was wrong, so therefore the control was in "Update" mode. If the SelectedCamp property of the control is set (and this property is of type Camp). At this point we create a Linq to Entitities query where we ask the domain service to Include the Events associated with the specified camp.
Once the response from the query arrives, we iterate through every Event object that is associated with the camp. For every event that was received, we check to see if it exists in our ObservableCollection data source. If it does, we set the IsChecked property to true for that item. Once we data bind the grid, all events that are associated with a specific camp will be "Checked".
Mission accomplished.
Few words on Database Structure, Domain Models generated by the Entity Framework, and WCF RIA.
Well, as it turns out EF will get you maybe 80% there out of the box. The tool is not intelligent enough to know what a many-to-many relationship is. In the case with camp and events we have the following structure:
camp -> participates in many -> events
(many) events -> have many -> camps (as participants)
So to make this happen we need a "joiner" table between camps and events. To do this properly, the joiner table should in theory have at the very least two columns:
CampId -> Foreign Key
EventId -> Foreign Key
Now to create a primary key for the Table, we should have:
CampId + EventId -> Composite Primary Key.
Making our table have only 2 fields. Now this is super important because this relationship creates the Navigation property possible in EF.
When the domain model is generated, the EF will not create the joiner table in the model. However to enable the navigation property between Camp and Event and vise versa there are a couple of things that have to happen on the underlying Domain Service meta data object.
**1. Locate the Camp metadata info. Decorate the IEnumerble<Event>Events property with:
[Include]
[Association("CampEvent", "CampId", "EventId", IsForeignKey=True)]
And to explain what those mean: The Include says whenever you query the domain model, please include every Event for the specified camp(s). The Association says there is an association table between camp and event for the navigation property to work. In the lookup table the camp has CampId identifier and Event has EventId. Use those to find all Events for the specified camp(s)**.
2. Do the same for whatever other navigational properties you have.
I'm developing a WinForms application (.Net 3.5, no WPF) where I want to be able to display foreign key lookups in a databound DataGridView.
An example of the sort of relationship is that I have a table of OrderLines. Orderlines have a foreign key relationship to Products and Products in turn have a foreign key relationship to ProductTypes.
I'd like to have a databound DataGridView where each row represents an orderline, displaying the line's product and producttype.
Users can add or edit orderlines direct to the grid and choose the product for the order line from a comboBoxColumn - this should then update the producttype column, showing the producttype for the selected product, in the same row.
The closest to a good fit that I've found so far is to introduce a domain object representing an orderline then bind the DataGridView to a collection of these orderlines. I then add properties to the orderline object that expose the product and the producttype, and raise relevant notifypropertychanged events to keep everything up to date. In my orderline repository I can then wire up the mappings between this orderline object and the three tables in my database.
This works for the databinding side of things, but having to hand code all that OR-mapping in the repository seems bad. I thought nHibernate would be able to help with this wiring up but am struggling with the mappings through all the foreign keys - they seem to work ok (the foreignkey lookup for an orderline's product creates the correct product object based on the foreign key) until I try to do the databinding, I can't get the databound id columns to update my product or producttype objects.
Is my general approach even in the right ballpark? If it is, what is a good solution to the mapping problem?
Or, is there a better solution to databinding rows including foreign key lookups that I haven't even considered?
I think the problem you're having is that when you are binding to a grid, it is not enough to support INotifyPropertyChanged, but you have to fire the ListChanged events in your IBindingList implementation and make sure that you override and return true for the SupportsChangeNotification property. If you don't return true for this, the grid won't look for it to know if the data has changed.
In .NET 2.0+, you can create a generic collection using the BindingList class, this will take care of most of the nastiness (just don't forget to override and return true for the SupportsChangeNotification property).
If the class you use for data binding has a property that is a collection (such as IBindingList or BindingList), then you can bind the foreign key grid to that property directly. When you configure the bindings in the Forms designer, just select the collection property as the data source for the grid. It should "just work". The only sneaky part is making sure that you handle empty or null collections the right way.
welcome to StackOverflow :)
Normally what you would do is base the information in the drop down on two values ValueMember and DisplayMember.
The ValueMember is the source of the actual controls value (this will be the key value in the order line), the display member is the value that is displayed to the user instead of the value (this will be the FK value).
Is there no particular reason you cannot just return all the data required and set these properties?
Here's a good "How Do I" video that demonstrates data binding:
http://windowsclient.net/learn/video.aspx?v=52579
Well, I don't know whether it's supported by the DataGridView, but when you're doing regular WinForms databinding (say, to a regular TextBox) you can use property paths to navigate through object relationships.
Something like this:
myTextBox.DataBindings.Add("Text", anOrderLine, "OrderedPart.PartNumber");
Would be worth seeing if this works in your situation too.
My original question obviously wasn't clear, sorry about that.
The problem wasn't with databinding to a DataGridView in general, or with the implementation of a DataGridViewComboBoxColumn - as the people who have answered already rightly say, that is well documented on the web.
The problem I've been trying to solve is with the refresh of properties that are drilling down through relationships.
In my orders example, when I change the value of the "Product" column, the "Product Type" column is not being updated - even though in the code I am setting the property and firing the NotifyPropertyChanged event. (In debug I go to all the right places)
After a lot of poking around I realised that this was not even working when I directly set the "Product Type" property of datasource, rather that setting it in the "Product" setter.
The other thing that I believe has me back on the right track is that when I provide a mocked dataccess layer, created in the main form, everything works fine.
Also, when I copy the IList made by nHibernate to a IBindingList - everything again appears fine.
So the problem is I think with threading and the NotifyPropertyChanged events being lost when using certain datasources, in certain ways (wish I could be more definitive than that!)
I'm going to keep researching better ways of resolving this than copying the IList to the IBindingList - maybe I need to learn about thread marshalling.
Edit
I've now developed a solution that solves the issue and think I understand what was confusing me - it appears that anything but basic property databinding doesn't play nicely for lists that aren't derived from BindingList - as soon as I was trying to databind to properties that fired chained NotifyPropertyChanged events, things went haywire and my events got lost.
The data access solution I have now is using a variation of the Rob Conery IRepository pattern, returning my collections to be bound as a custom class I made, a SortableBindingLazyList that derives from BindingList, implements the Sort Core methods and also stores its internal list as a query, delaying the list materialisation.