A static constructor for class SourceManager
goes through all modules/classes and discovers all classes that implement ISource
. It will instantiate each one of these and expose an IEnumerable
of them as a static property called IEnumerable<ISource> Sources
. For simplicity ISource
has two properties, DataTable Table { get; }
and string UniqueName { get; }
. When instantiated each different ISource
is responsible for populating its Table
from SQL, MDX, etc. For all the ISource
's I've written thus far, loading the Table
with all DataRow
s when instantiated has been sufficient. However I now have a situation where I'd like to load the Table
with DataRow
's lazily, rather than all up front. How do I do this? I will walk through an example.
PermissionSource
implements ISource
. Its Table
property, that has a private set
is given a value of new PermissionDataTable()
. Its UniqueName
is "Permissions"
. As of right now there are no permissions loaded from the database into this Table
property.
ISource permissionSource = SourceManager.Sources.
Where(s => "Permission".Equals(s.UniqueName)).First();
Now we've obtained the PermissionSource
, but through an interface. Let's get a permission.
DataRow row = permissionSource.Table.Rows.Cast<DataRow>().
Where(r => r["PermissionName"].Equals("PermissionName")).First()
I've overriden the Rows
property in PermissionDataTable
so that the above, somehow, gets the value of the permissions associated with "PermissionName"
in the database. Other permissions are not loaded.
I don't have a choice in the permissions system and I don't have a choice to not use a DataTable
.
EDIT:
In my example I would need to override the Rows
property of DataTable
. Rows
, though, is a DataRowCollection which is sealed
. Thus there isn't much that can be done in terms of creating a minimal custom DataTable implementation like I want to do.
I think what you are looking for is something like LinqToSql, where each of your ISources could return a Table instead of a DataTable. This would allow you to use dynamic queries like you have given in the example, and load only the requested data, and only when needed. I don't know if you will be able to find LinqToSql providers for all of your data sources. If that becomes a problem, you can try to use Entity Framework, as previously suggested.
The following example adds a timestamp value to the DataTable through the ExtendedProperties property.
I am not sure I understand your restrictions in using a DataTable, but one thing I've done in the past when I needed to "refresh" the data in a DataTable or repopulate it using different criteria is to create a new class derived from DataTable that includes a reference to a DataAdapter with the connection and selection information originally used to fill the DataTable.
For example, the DataTable sub-class could look something like the
LazyDataTable
code below. Note that I have added several different methods of accessing the Rows. They might make more sense after taking a look at thePermissionSource
and mainProgram
code near the end of this post. Also, please note that I have not included all of the details related to properly opening and closing database connections in every case. How you handle that will depend on your model for database access (e.g. connection pooling, shared connections etc).Then your
PermissionSource
would create aLazyDataTable
and set the DataAdapter (including the connection and SELECT command) appropriately. It wouldn't fill the DataTable, but would instead return it empty, to be filled later, by the application code. So yourPermissionSource
might something like the code below. I've usedSystem.Data.OleDb
data objects as an example, but you would use whatever ADO providers you want.Your main program code would use
PermissionSource
andLazyDataTable
as follows:You can certainly mix and match parts of the LazyDataTable shown here to achieve exactly what you want within your application constraints. It would of course be much better if you could switch to a different model of sharing data, but if you MUST return a DataTable from each Source, then at least you can return a more functional DataTable when necessary by subclassing it as I've demonstrated here. This allows you to pass back more information, which you can use to fill the table as you see fit. I would still encourage you to look into LinqToSQL as well as possibly trying to switch to simply passing back a DbDataReader or some other object similar to the LazyDataTable I've shown here that will allow you to both customize the original query (e.g. by using the
SetSelectParam
method) and also to read the data in one row at a time.Hope that helps!
It's probably no use any more, but this might do it.