Why is the DataSourceSelectArguments sealed? - asp.net

Does anybody know the logic behind making DataSourceSelectArguments sealed?
I've implemented a custom DataSource (and related classes) for some custom business objects and custom WebControls. When thinking in filters (like in a grid) I discovered that the DataSourceSelectArguments is sealed. Surely, I'm missing something. (Maybe the logic is related to the fact that is nonsense to ask the DB again, just for filtering?, just a guess.)

Sorry for the delay, I was on holydays. :)
The problem is that a DataBoundControl such as ListView has a SortExpression property, but not a FilterExpression. It is fine to implement a sortable grid/list with a ListView by means of a IButtonControl WebControl that fires a PostBack and a Command event. Then you use the SortExpression or the Sort method and pass a sort expression that will fill the DataSourceSelectArguments.SortExpression and pass it to the DataSource which can construct the apropiate SQL statement (in my case) to retrieve the Data from the DB. This allows for separation between the Data and the WebControl that displays it, IMHO.
Following this pattern I was about to implement a filter by filling an extra parameter object in my DataSourceSelectArguments with the requested filter and I will have called Sort, which would have passed this arguments object to the DataSource, where I would have constructed the appropiate select clause.
I've finally solve it by "coding" the filter information in the SortExpression, but I find it ugly (for the name, in the first place: sort != filter), and I was wondering if there's a more appropiate way of doing this or if I'm missing something that is more subtle.
Edit:
Maybe a better approach would be to override ListView's PerformSelect method and ask my own implementation of the DataSourceView if it can filter, then call a special ExecuteSelect method that accepts a special DataSourceSelectArguments with a filter object. Taking care not to do anything that will break when someone use the custom ListView with a non-enhanced DataSourceView, of course.

My guess is because the class is a dumb data transfer object merely used to pass arguments to a method.
This class itself doesn't have any operations defined on it, thus what sort of polymorphism would you expect? For example, the existing methods will only know about the properties of this class, which are all settable, so there's no need to override the properties. If you added new properties, they would get ignored.
For your own method, can you create your own Arguments class that just happens to have all the same properties?

Related

Can't databind an IEnumerable of DataRows? HttpException?

I have a function that returns a DataTable that I can databind to a DropDownlist or Repeater just fine. However, if I databind an IEnumerable of the DataTable's DataRows, I get an HttpException: "DataBinding: 'System.Data.DataRow' does not contain a property with the name 'some_column'".
repeater.DataSource = ThisReturnsDataTable(); // Works fine
repeater.DataSource = ThisReturnsDataTable.AsEnumerable(); // HttpException
Why is this?
I'm not looking for a solution to the problem, like for example:
repeater.DataSource = ThisReturnsDataTable().AsEnumerable().Select(
x => new {some_column = x["some_column"]});
I simply want to know why the databinding with an IEnumerable of DataRows fails.
I found a pretty good explanation here, although his first solution to the problem, AsDataView(), doesn't seem to work/exist (in 3.5, at least). CopyToDataTable() works swimmingly, though.
.Net DataTables can be very useful when writing data-driven
applications. However, they have one limitation: There is no obvious
way to databind a grid (or other control) to an arbitrary list of
datarows from a table. You can bind to an entire table directly by
setting a DataSource to the DataTable itself, and you can bind to a
subset of a table by creating a DataView with a filter.
In general, you cannot bind to an IEnumerable (eg, a LINQ query);
the databinding infrastructure can only handle an IList (non-generic)
or an IListSource. This is true for any kind of datasource.
Therefore, to bind to any LINQ query, you need to call .ToList(). (Or
.ToArray())
However, when binding to a DataTable, you can’t even use a
List. If you try, you’ll get four columns (RowError,
RowState, Table, and HasErrors) and no useful information. This
happens because the List doesn’t tell the databinding
infrastructure about the special properties of the DataRows. To
understand the problem, some background is necessary
Databinding is controlled by the ListBindingHelper and TypeDescriptor
classes. When you bind to a list, the
ListBindingHelper.GetListItemProperties method is called to get the
columns in the list. If the list implements the ITypedList interface,
its GetItemProperties method is called. Otherwise, it will use
TypeDescriptor to get the properties of the first item in the list.
(this uses reflection)
The DataView class (which DataTable also binds through, using
IListSource) implements ITypedList and returns
DataColumnPropertyDescriptors that expose the columns in the table.
This is why you can bind to a DataView or DataTable and see columns.
However, when you bind to a List, there is no ITypedList that
can return the columns as properties. It therefore falls back on
reflection and shows the physical properties of the DataRow class.
To solve this issue, you need to wrap the list in a DataView so that
you can take advantage of its ITypedList implementation. You can do
that using the AsDataView() method. This method is only available on
the DataTable and EnumerableRowCollection classes; it cannot be
called on an arbitrary LINQ query. You can only get an
EnumerableRowCollection by calling special versions of the Cast,
OrderBy, Where, and Select methods from a DataTable.
Therefore, you can databind to a simple LINQ query by calling
AsDataView() on the query. To bind to a List, or to a more
complicated query, you can use an ugly hack:
List<DataRow> list = ...;
grid.DataSource = datatable.AsEnumerable()
.Where(list.Contains)
.AsDataView();
The AsEnumerable() call is not needed for typed datasets.
You can also call CopyToDataTable(), which will works [sic] on an arbitrary
IEnumerable. However, it makes deep copies of the rows, so
it isn’t helpful if you want the user to update the data, or if you
want the user to see changes made (in code) to the original datarows.
From: http://blog.slaks.net/2011/01/binding-to-lists-of-datarows.html
I could be wrong, but I believe instead of doing the .Where clause, you should be able to do something like this:
DirectCast([datatable].AsEnumerable, EnumerableRowCollection(Of DataRow)).AsDataView()

ObjectDataSource has no values to insert

I'm using an ObjectDataSource to perform CRUD operations. For some reason I am getting an "ObjectDataSource 'ObjectDataSource1' has no values to insert. Check that the 'values' dictionary contains values."
Any suggestions?
I understand that this control inherits from the ObjectDataSource Control. According to the documentation http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.objectdatasource.insertmethod.aspx
If the DataObjectTypeName property is set, the method is resolved in a different way. The ObjectDataSource looks for a method with the name that is specified in the InsertMethod property that takes one parameter of the type that is specified in the DataObjectTypeName property.
That's how my ObjectDataSource Control is setup.
<asp: ObjectDataSource ID="ObjectDataSource1" runat="server"
DataObjectTypeName="MyApplication.Entities.Domain.MyObject" ConflictDetection="CompareAllValues"
OldValuesParameterFormatString="original{0}" SelectMethod="GetUserDisplays"
InsertMethod="CreateMyObject" UpdateMethod="UpdateMyObject" DeleteMethod="DeleteDisplay">
</asp:ObjectDataSource>
I set a breakpoint on the InsertMethod, but the application does not even hit it when I try to save my form. I suspect the DataObjectType is not being instantiated properly for some reason.
I'm trying to perform the Insert operation in the EditForm of an ASPxGridview control and the DataObjectType is an EF POCO which has some additional properties (marked virtual) in it to load related entities from the ObjectContext. I think this may be the problem but don't know how to fix it (have looked everywhere!!!).
Any help would be greatly appreciated!
Although I have not been able to determine exactly why the DataObjectType is not being instantiated automatically, I realized that there was an input parameter that needed to be added prior to calling the InsertMethod on the ObjectDataSource. To do this, I needed to add the input parameter (in my scenario anyway) in the Inserting event. Thanks to another post on StackOverflow I was able to figure out that I needed to remove the 'DataObjectTypeName' attribute from the ObjectDataSource for the Inserting event to fire.
I didn't notice a "TypeName" attribute in your ObjectDataSource definition. The DataObjectTypeName according to MSDN is used to identify the class "that the ObjectDataSource control uses for a parameter in an update, insert, or delete data operation, instead of passing individual values from the data-bound control." If the classes are the same (i.e. the CRUD methods class and the data object definition class) then both attributes should be assigned to the same class. If however, your methods are contained in a separate class from your DTO then you would identify each individually.
This helpful post solved the issue for me:
http://dyslexicanaboko.blogspot.com/2012/09/objectdatasource-has-no-values-to.html

Data binding support in O/RM tools, how to detect

I want to verify that a generated class (single entity or collection) from an O/RM tool is data binding compatible.
I read that supported data binding types in WCF are: one time, one way, two way, one way from source in WCF. But how about "old school" .NET 1.1 data binding ?
It looks kind of difficult to check in code what kind of data binding support there is. You also have difference in runtime and design time data binding support. When reading some webpages I read different kind of implementations: implement IList, IComponent, INotifyPropertyChanged, IBindingList.... pffffff I don't know exactly where to look for...
You can databind to virtually any class. Let's imagine you create a very simple class, with a few properties, say for instance, Person with a Name and Age. I am talking about a plain simple class with absolutely nothing fancy about it.
If you create an instance of Person, you can do several things with it, and I will assume you are working with Windows Forms, but this mostly applies to other frameworks:
- You can bind its properties to properties of controls.
- You can bind it to datagrids, lists, etc. In the former case you can set mappings of which properties bind to which columns. In the latter, which property is displayed in the list, which property is the value selected by the user.
- Even better, you can bind it to a bindingSource.
Binding a single instance to a grid or a list isn't that useful, so what usually is done is that you create a list of instances and bind those to the grid. Even more correct is to bind the list to a bindingsource and the grid to the bindingsource also.
You can see a good article here about how to do all this.
Now, about all the interfaces you mention, they all only add more value to the databinding experience. Let's talk about a few of them.
INotifyPropertyChanged. Person is not less "databindable" than any other object if it does not implement this interface. What instances of Person are not able to do, however, is notify the controls their properties are bound to that the latter have changed. Try this: Bind the Name property of a Person instance to the Text property of a TextBox. Create a button that when clicked changes the value of that instance's Name. You will see the TextBox does not update after clicking the button. If, on the other hand, you implement INotifyPropertyChanged and have the setter of the Name property raise the PropertyChangedEvent that is defined by the interface, after repeating the experience, you will see that the textbox is updated automatically.
IEnumerable. If instead of a single Person, you want to databind not to a set of people, you can create a list of people and databind to that list. Let's take for instance, List lst = new List(); How do the databinding controls like datagrid, bindingSource, etc., know you want to bind to a set of Person(s) and not to the properties of lst itself? It is because List implements IEnumerable. So, whenever you bind these controls to an instance of anything that implements IEnumerable, the controls know that you intend to bind not to the properties of the list, but to the instances the list refers to. How do they know the type of objects the list contains? To be more generic and support any type of IEnumerable implementation, they just check the type of the first element in the list and assume all others are equal.
IBindingList: Even if Person implements IPropertyChanged, if you group instances of Person into a List bind that list to a control and, by code, change the value of a property of one of the instances, you will see nothing happen in the screen. This happens because Person is notifying, not the binding source, but the list. But the list wasn't made for databinding, so it is not listening, nor propagating the event to the control. Lists that implement IBindingList, like BindingList, offer a better databinding support precisely by listening to the PropertyChangedEvent events of their contents and propagating them up to the databound control.
I am affraid I have given you no way of determining if an object is databoundable, because virtually all them are, but I hope I've given you a way of determining different levels of databinding support (INotifyPropertyChanged and IBindingList). I am assuming you know how to check for these via reflection.
Any instance of a class with properties is data bindable. (in fact instances of any class with fields or properties at all are data bindable)
Using reflection in .NET makes it very easy to discover/use data in an object. (at a small performance cost)
In order to answer this question you'd need to provide the specific usage scenarios you'll be encountering.
Rui gives some good explanation of different common data binding patterns, but each of them is for solving specific problems.
The right answer is always dependent on the context.
:)

ASP.Net: Is it possible to skip databinding of an element if an error occurs?

I use a lot of repeaters for different elements of our sites, and I've always wondered if there was a way to have the repeater skip an element if an exception occurs instead of having the whole page crash?
In particular, I've inherited a system from another developer that using a similar design, however he didn't include any kind of validation for his business objects, and it a single property is missing, the whole thing goes up in smoke.
Any suggestions?
Thanks in advance!
The simplest suggestion I can offer is the check the validity of the data before it's passed to the repeater. I don't believe there's any way to get the stock repeater to skip a data element on error.
The other approach is to build your own repeater, inheriting from the base Repeater, to add that functionality but I've no sample code to offer. Perhaps someone else may be able to help there.
The way I see it, you have at least three options.
You could create a custom repeater control that inherits System.Web.UI.WebControls.Repeater and override the databinding behaviour to be more try-catchy (probably fail silently on databinding errors). You couldd then easily replace all instances of the standard Repeater with this new one.
You could filter your datasources before databinding to remove items you know are going to cause problems beforehand. This option may be quite laborious and something of an iterative process.
You could try adding default values to the business objects, so that the properties you're binding to return a default instance rather than null (not nice either).
That's my thoughts anyway.
One question - you say "when a property is missing". Do you mean he's using a style of databinding syntax that offers no compile-time checking and is referencing properties that don't exist, or is referecing properties that are null?
Edit
OK, so you're referencing properties that are null. If you have access to the code for the business objects you could modify them so they return a new, non-null instance (this is the third option I gave).
You don't say if you're using .net 3.5, but I'll assume you are. You could add a new property "IsValidForDataBinding" on to each of your business objects. In the getter logic you could check each of the necessary properties and sub-objects to check for validity, non-nullness etc and return a bool. When you come to bind your repeater, write a simple linq statement that filters-out the invalid items (i.e. where IsValidForDataBinding = false). Having said that, I still think that writing a derived repeater control could be your easiest option.
Have you tried using string.isnullorempty("the string") to check for a value before referencing the property?
Here's a reference: MSDN

Why should I create my child controls in CreateChildControls() on a CompositeControl?

Ok so the obvious answer is, because the flow of a composite control demands my childcontrols to be created at a certain point in time. I got a problem i think other people must have had as well.
My control is a composite "container/collection" control. It will be fed with an object and based on that objects data it will create a number of childcontrols. So my control will render a header (always) and x-number of, say TextBox controls (based on the object it was fed with).
I'm creating my header in CreateChildControls() obviously, but i can't possibly create my TextBoxes there as well, because i don't know if the object (to base the TextBoxes on) has been fed yet? I thought of exposing a property/method to set/fed the object through, but i'm not sure when it will be called.
So what do i do? I mean i can't possibly create the TextBoxes in CreateChildControls() or can I? I mean - when is CreateChildControls() called - i know i can call EnsureChildControls() (which i already do in a property to set the innerText of the header - since i need the header to be created before setting its innerText obviously).
How about this
var c = new MyContainerControl();
c.Header = "fun";
c.TextBoxObject = myTextBoxes;
That would raise an error (or at best not create any TextBox'es) if i put the building of the TextBoxes in CreateChildControls().
Would it be more sane to instead just store the Header in a member variable and thus not having to call EnsureChildControls() in the exposed method/property setting the Header innerText. I just don't like this aproach much, since it would be complicating things by adding extra logic to store temporarely and later having to figure out when to set it (probably in PreRender).
Also i guess i could make some kind of Databound control, ensuring the data be present at the time of calling .DataBind(). I really don't like this either since last i looked at creating databound controls it got very complicated.
This really should be an easy task to solve - I know I'm missing something somewhere...
what you're describing IS a databound control. And yes, it's somewhat complicated, but it's the proper design paradigm for this type of instance.
That said, had you considered utilizing the repeater control rather than trying to roll out your own composite which behaves in the exact same manner? Rather than passing it a random object, pass it a collection or an iList with the number of text areas you're wanting.

Resources