List & Label 20 ships with more than twenty data providers that can be used to easily bind your reports to the data you require. Some of you might not even have noticed, because a lot of the magic happens under the hood. You can easily assign a SqlConnection instance to the DataSource property and will be presented with all parsable tables from this connection in the Designer. LL simply takes whatever you throw at it and tries to make sense of it. A DataSet, DataViewManager or a simple enumerable object are handled in the same way.
The providers basically fall into four major groups:
- Database connectors. We currently do support (in no particular order) Microsoft SQL Server, PostgreSQL, MySql, SQLite, Oracle, Firebird, DB2, Access, generic ADO.NET, OleDB, ODBC, OData and Google BigQuery. Besides, we ship a base class for SQL type data providers (DbConnectionDataProvider) that can be inherited from. This base class provides all the handling required to parse queries, create parametrized queries and translate filters to the database syntax. For some real world code examples how to correctly inherit from this class, we provide the sources to some of the providers on Codeplex.
A couple of other providers that fall in this group help cover even more data sources. Through cooperation with RSSBus and TasteIT, we are able to support most RSS bus connectors as well as Progress data sources.
- File/web based connectors. These cover data from XML, CSV, XLS, JSON and REST sources.
- Business objects. The ObjectDataProvider offers thorough support for business objects via reflection. It supports hierarchical data sources (i.e. objects containing lists of objects again), typed and untyped enumerations and even supports more advanced interfaces like ITypedList for typing untyped collections and IBindingListView for sorting. You can just as well use this provider for EntityFramework data sources.
- Meta providers. This group is probably the least known one, although you can do really fancy things with these providers. Just keep reading if this sounds interesting.
The providers from group 1-3 are very straight forward and most of the time don’t need to be created explicitly. However, as some of the providers have different contructor overloads or offer interesting events it’s always a good idea to check out the documentation for your particular provider. For example, a quite frequent support request we receive goes like “I just bound List & Label to my business object, but the designer will not come up”. Depending on the complexity of your object, this might be expected behavior: the default constructor of the ObjectDataProvider will set the recursion depth to “10”, i.e. all relations are parsed ten levels deep. Think of self-relational objects with some hundred enumerable properties and you can easily wait for a couple of minutes until reflection has done its work here. Enter the explicit contruction of the provider:
ObjectDataProvider provider = new ObjectDataProvider(myBusinessObject, 2);
This will restrict the recursion depth to “2” and the Designer will open up lightning fast. For more fine tuning, the provider also has an event “HandleEnumerableProperty” where you can decide case-by-case if the further recursion should be stopped or not.
The meta providers always need to be constructed explicitly. We currently have 2 ½ of them ;-):
a) DataProviderCollection. This provider allows you to mix different other providers in one data source. This way, you can offer the contents of an Excel sheet and a SQL database in just a few lines of code:
DataProviderCollection collection = new DataProviderCollection(); collection.Add(new XlsDataProvider(@"D:\datasources\Orders.xlsx", true); collection.Add(new SqlConnectionDataProvider(myConnection)); LL.DataSource = collection;
b) InMemoryDataProvider. This provider wraps other providers in an in memory data base. While this may take a tad more time (the data needs to be read first) it offers entirely new features to otherwise restricted providers. For example, there is no way to sort or (natively) filter a CSV data source. Also, you cannot easily add relations between tables from different providers like a CSV file and an Excel sheet.
Using the InMemoryDataProvider, all you need to do is:
CsvDataProvider csv = newCsvDataProvider(@"D:\datasources\Customer.txt", true,"Customers",','); XlsDataProvider xls = new XlsDataProvider(@"D:\datasources\Orders.xlsx", true); InMemoryDataProvider inmem = new InMemoryDataProvider(); inmem.AddTable(csv, "Customers"); inmem.AddTable(xls, "Orders"); inmem.AddRelation("Customers", "Orders", "CustomerID", "CustomerID"); LL.DataSource = inmem;
c) RemoteDataProvider. This provider is not public yet, however we use it internally for our great new Report Server product. It features the complete wrapping of a provider on the server side, opens up a communication channel to a client and can be used there just as if it was a local data source. We’ll probably release this provider with version 21, as we’ve already seen a couple of requests for this technology. To use a famous developer quote: “it works on my machine” :-).