Random Dev Notes

June 7, 2011

Retrieving Auto Generated Primary Key Values on Insert

Filed under: Development — Tags: — Tom Brothers @ 12:17 am

The default IQToolkit Insert method always seemed a little odd to me in that it didn’t populate an auto generated primary key property after executing the Insert statement.  The following image demonstrates this issue.  Notice how the Categoryid is 0 after the insert.

image

The toolkit does provide a way to get the primary key value but the process isn’t very intuitive (especially after working with other ORMs like LINQ to SQL).  Here is how the toolkit provides a way to get the primary key value.

image

One problem with this approach is that it isn’t an option when using the Unit of Work (EntitySession) approach.

Personally, I ‘d rather have a simpler approach such as the following.

image

 

To achieve this simpler approach I needed to create a class that could handle the inserting of an Entity.  This class needed to read the mapping information to see if the Entity had an auto-generated primary key.  If the Entity did have an auto-generated primary key then the class needed to create an Insert function that could retrieve the new value and set it on the Entity instance.  However, if the Entity didn’t have an auto-generated primary key the class would return a function that called the standard IQToolkit Insert method.

Here is the class that I came up with:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using IQToolkit;
using IQToolkit.Data;
using IQToolkit.Data.Common;
using IQToolkit.Data.Mapping;
 
namespace IQToolkitContrib {
    /// <summary>
    /// This class handles processing the Insert statement with special consideration given to AutoGenerated Primary Keys to ensure that 
    /// the Entity's Primary Key property is updated after the Insert.
    /// </summary>
    /// <typeparam name="T">Entity Type.</typeparam>
    internal class DbEntityInserter<T> {
        private readonly IEntityTable<T> entityTable;
        private readonly Type entityType = typeof(T);
        private readonly MappingEntity mappingEntity;
        private readonly PropertyInfo primaryKey;
        private readonly Func<T, int> insert;
 
        public DbEntityInserter(IEntityTable<T> entityTable, DbEntityProvider provider) {
            if (entityTable == null) {
                throw new ArgumentNullException("entityTable");
            }
 
            this.entityTable = entityTable;
 
            if (provider != null) {
                this.mappingEntity = provider.Mapping.GetEntity(this.entityType);
                this.primaryKey = this.GetPrimaryKey(provider);
            }
 
            this.insert = this.GetInsertFunction();
        }
 
        /// <summary>
        /// Executes the Insert for the Entity.
        /// </summary>
        /// <param name="instance">Entity instance.</param>
        /// <returns>Returns the Insert row count.</returns>
        public int Insert(T instance) {
            return this.insert(instance);
        }
 
        /// <summary>
        /// Inspects the Entity mapping information to determine if the standard Insert statement should be used or if the insert statement should include 
        /// the extra step of retrieving the AutoGenerated primary key.
        /// </summary>
        /// <returns>Returns the Insert function.</returns>
        private Func<T, int> GetInsertFunction() {
            if (this.primaryKey != null && this.IsGeneratedPrimaryKey()) {
                // Create a type array for the generic types for the Insert<T, S> method.
                Type[] genericTypes = new Type[] { this.entityType, this.primaryKey.PropertyType };
 
                LambdaExpression insertExpression = this.GetInsertExpression(genericTypes);
                MethodInfo insertMethod = this.GetInsertMethod(genericTypes);
 
                return instance => {
                    object id = insertMethod.Invoke(null, new object[] { this.entityTable, instance, insertExpression });
 
                    // Set the primary key property to the new Id value.
                    this.entityType.GetProperty(this.primaryKey.Name).SetValue(instance, id);
 
                    // Assuming if we got this far without an exception then the insert worked.
                    return 1;
                };
            }
 
            // Do the insert statement as normal if the Entity doesn't have an AutoGenerated primary key.
            return instance => this.entityTable.Insert(instance);
        }
 
        /// <summary>
        /// Gets a reference to the IQToolkit.Updatable.Insert method.
        /// </summary>
        /// <param name="genericTypes">Generic Types Array for the Expression.</param>
        /// <returns>Returns IQToolkit.Updatable.Insert MethodInfo.</returns>
        private MethodInfo GetInsertMethod(Type[] genericTypes) {
            // MethodInfo for: (IQToolkit.Updatable) public static S Insert<T, S>(this IUpdatable<T> collection, T instance, Expression<Func<T, S>> resultSelector)
            MethodInfo mi = typeof(IQToolkit.Updatable).GetMethods()
                                                       .Where(d => d.Name == "Insert" && d.IsGenericMethod && d.ReturnType.FullName == null)
                                                       .First();
 
            return mi.MakeGenericMethod(genericTypes);
        }
 
        /// <summary>
        /// Creates an Expression that will be passed to the IQToolkit.Updatable.Insert method
        /// </summary>
        /// <param name="genericTypes">Generic Types Array for the Expression.</param>
        /// <returns>Returns an Expression.</returns>
        private LambdaExpression GetInsertExpression(Type[] genericTypes) {
            // Create type for Expression<Func<T, S>>.
            Type functionExpressionType = Expression.GetFuncType(genericTypes);
 
            // Create an Expression Parameter.
            var parameter = Expression.Parameter(this.entityType, "instance");
 
            // Create a Lambda Expression for the Func<T, S> call. 
            // Expression example:  x => x.Id
            return Expression.Lambda(functionExpressionType, Expression.Property(parameter, this.primaryKey.Name), parameter);
        }
 
        /// <summary>
        /// Use reflection to determine if the primary key column was mapped as a generated column.
        /// </summary>
        /// <returns>Returns true if the primary key is generated by the database.</returns>
        private bool IsGeneratedPrimaryKey() {
            // Get a reference to the internal method GetMappingMember.
            MethodInfo getMappingMember = this.mappingEntity.GetType()
                                                             .GetMethod("GetMappingMember", BindingFlags.NonPublic | BindingFlags.Instance);
 
            // Invoke GetMappingMember.
            object mappingMember = getMappingMember.Invoke(this.mappingEntity, new object[] { this.primaryKey.Name });
 
            // Get the Column property from the mappingMember.
            ColumnAttribute columnAttribute = (ColumnAttribute)mappingMember.GetType()
                                                                            .GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance)
                                                                            .GetValue(mappingMember);
 
            return columnAttribute.IsGenerated;
        }
 
        /// <summary>
        /// Gets the primary key if the Entity has only one column for the primary key.  The assumption is that composite
        /// primary keys don't need to be retrieved after executing the Insert statement.
        /// </summary>
        /// <param name="provider">DbEntityProvider instance.</param>
        /// <returns>Returns the PrimaryKey PropertyInfo.</returns>
        private PropertyInfo GetPrimaryKey(DbEntityProvider provider) {
            MemberInfo primaryKeyMemberInfo = provider.Mapping
                                                      .GetPrimaryKeyMembers(this.mappingEntity)
                                                      .SingleOrDefault();
 
            return primaryKeyMemberInfo as PropertyInfo;
        }
    }
}

The next step was to hook the DbEntityInserter into the IQToolkit insert process.  This was handled by creating a decorator class that implemented IEntityTable.

Here is the class that I came up with:

using System;
using System.Collections.Generic;
using System.Linq;
using IQToolkit;
using IQToolkit.Data;
 
namespace IQToolkitContrib {
    /// <summary>
    /// This class wraps the actions to the EntityTable to provide a hook into the Insert method.
    /// </summary>
    /// <typeparam name="T">Entity Type.</typeparam>
    internal class DbEntityTable<T> : IEntityTable<T> where T : class {
        private readonly IEntityTable<T> entityTable;
        private DbEntityInserter<T> inserter;
 
        public DbEntityTable(IEntityTable<T> entityTable) {
            if (entityTable == null) {
                throw new ArgumentNullException("entityTable");
            }
 
            this.entityTable = entityTable;
        }
 
        #region IEntityTable<T> Members
 
        public int Delete(T instance) {
            return this.entityTable.Delete(instance);
        }
 
        public T GetById(object id) {
            return this.entityTable.GetById(id);
        }
 
        public int Insert(T instance) {
            if (this.inserter == null) {
                this.inserter = new DbEntityInserter<T>(this.entityTable, this.Provider as DbEntityProvider);
            }
 
            // Using the DbEntityInserter to handle the insert.
            return this.inserter.Insert(instance);
        }
 
        public int InsertOrUpdate(T instance) {
            return this.InsertOrUpdate(instance);
        }
 
        public int Update(T instance) {
            return this.entityTable.Update(instance);
        }
 
        #endregion
 
        #region IEntityTable Members
 
        public int Delete(object instance) {
            return this.entityTable.Delete(instance);
        }
 
        object IEntityTable.GetById(object id) {
            return this.entityTable.GetById(id);
        }
 
        public int Insert(object instance) {
            return this.Insert(instance as T);
        }
 
        public int InsertOrUpdate(object instance) {
            return this.entityTable.InsertOrUpdate(instance);
        }
 
        public IEntityProvider Provider {
            get { return this.entityTable.Provider; }
        }
 
        public string TableId {
            get { return this.entityTable.TableId; }
        }
 
        public int Update(object instance) {
            return this.entityTable.Update(instance);
        }
 
        #endregion
 
        #region IQueryable Members
 
        public Type ElementType {
            get { return this.entityTable.ElementType; }
        }
 
        public System.Linq.Expressions.Expression Expression {
            get { return this.entityTable.Expression; }
        }
 
        IQueryProvider IQueryable.Provider {
            get { return ((IQueryable)this.entityTable).Provider; }
        }
 
        #endregion
 
        #region IEnumerable Members
 
        public System.Collections.IEnumerator GetEnumerator() {
            return this.entityTable.GetEnumerator();
        }
 
        #endregion
 
        #region IEnumerable<T> Members
 
        IEnumerator<T> IEnumerable<T>.GetEnumerator() {
            return ((IEnumerable<T>)this.entityTable).GetEnumerator();
        }
 
        #endregion
    }
}

 

The final step was to simply hook into the Provider’s GetTable method and return an instance of the DbEntityTable.

Here is an example of a base class that I wrote to just that:

using System;
using IQToolkit;
using IQToolkit.Data;
 
namespace IQToolkitContrib {
    public abstract class DbEntityContextBase {
        private readonly DbEntityProvider provider;
 
        public DbEntityProvider Provider {
            get {
                return this.provider;
            }
        }
 
        public DbEntityContextBase(DbEntityProvider provider) {
            if (provider == null) {
                throw new ArgumentNullException("provider");
            }
 
            this.provider = provider;
        }
 
        protected IEntityTable<T> GetTable<T>() where T : class {
            string tableId = this.provider.Mapping.GetTableId(typeof(T));
            IEntityTable<T> table = this.provider.GetTable<T>(tableId);
 
            return new DbEntityTable<T>(table);
        }
    }
}

 

* This base class and a unit of work version can be found in the IQToolkitContrib download.

January 7, 2010

IQToolkitCodeGen (alpha version)

Filed under: Development — Tags: , , — Tom Brothers @ 11:40 am

When I first started using LINQ to VFP I didn’t mind manually writing Entity classes and mapping the data but after awhile I found it to become a tedious task.  So I decided to write a code generation application that would work with LINQ to VFP and the IQToolkit SQL Server Provider.  This application has really turned out to be a play thing for me so that I can get some hands on learning with WPF and Spark View Engine.  But before I’d allow myself to get to far into playing around I wanted to make sure I got the core functionality done.  At this point I have an alpha build available for anyone interested. 

image


Settings Overview:

image

As expected, you can use a full connection string to access VFP or SQL Server.  There are also a few unconventional connection options.  You can specify the full path to a dbc file or a specify a directory for free tables.  Both of these options will be used to create a connection string for VFP.  You can also provide a modified version of a SQL Server connection string that includes a pipe delimited list of databases (Example:  Data Source=.;Initial Catalog=Northwind|AspNet;Integrated Security=True). 

image
The Data Context Settings were designed with two different Data Contexts types in mind.  The first Data Context is an Entity Provider which is basically a class that has a property for each Entity.  This type of Data Context is what the IQToolkit Tests use.  The other type of Data Context is a based on a Repository Pattern which uses Generic methods instead of accessing an Entity property. 

The Data Context Settings allow you to specify the class name, output file, and namespace for both types of these Data Contexts.  The Base Class setting is for the Repository Data Context.

image
The Entity Settings allow you to specify the file extension, namespace, output path, and template.  There is only one Entity template available. 
 
image
The Mapping Settings can be used to create an Attribute Mapping class or an Xml Mapping file.


By default, the Entity Provider Template was designed to work with the Attribute Mapping Template and the Repository Provider Template was designed to work with the Xml Mapping Template.


Getting Started:

Enter all the setting values and then click the Load Data button.  Then the grids will be populated with the Tables, Columns, and Associations information.

The Tables grid is pretty simple to use.  Just check the checkbox in the Include column if you want an Entity class created.  The Entity class name can be specified using the grid’s Entity Name column.

image

The Columns grid shows the Columns of the selected row in the Tables grid.  This grid has a few more available options than the Table grid but is just as easy to use.  Check the checkbox in the Include column if you want the Entity class to include the property for the selected column.  In this grid, you can also change the name and type of the property as well as identify the primary key and indicate if it is an auto generated key.

image

The last grid shows the Associations.  This grid has an Include column and a Property Name column that can be set.

image

Click the Generate Files button after all the mapping information has been entered to complete the process.


Don’t like my templates?

The template files are distributed with this application so feel free to modify the templates as needed. Additionally, if you feel that you need to add a new template just add it to the appropriate folder and it will show up in the combo box after resetting the application.

This is a diagram shows the Template classes along with classes that they reference.

image

November 3, 2009

IQToolKit Data Provider Repository

Filed under: Development — Tags: , — Tom Brothers @ 1:44 am

Inspired by the GenericRepository found in “ASP.NET MVC Framework Unleashed.”, I decided to write a Repository class to work with the IQToolKit Data Providers.

The first step was to create an interface named IRepository.

using System.Linq;
 
namespace IQToolkitContrib {
    public interface IRepository {
        T Get<T>(object id) where T : class;
        IQueryable<T> List<T>() where T : class;
        void Insert<T>(T entity) where T : class;
        void Update<T>(T entity) where T : class;
        void Delete<T>(T entity) where T : class;
    }
}

The second step was to create an abstract class name ARepository.  This class implements the IRepository interface by creating all the methods as abstract methods.  This class also includes a method CreateGetExpression which returns an Expression that will be used to get an Entity Instance by Primary Key.  The Entity’s Primary Key Property Name will be provided by an abstract method named GetPrimaryKeyPropertyName.

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
 
namespace IQToolkitContrib {
    public abstract class ARepository : IRepository {
        protected Expression<Func<T, bool>> CreateGetExpression<T>(object id) {
            ParameterExpression e = Expression.Parameter(typeof(T), "e");
            PropertyInfo pi = typeof(T).GetProperty(this.GetPrimaryKeyPropertyName<T>());
            MemberExpression m = Expression.MakeMemberAccess(e, pi);
            ConstantExpression c = Expression.Constant(id, id.GetType());
            BinaryExpression b = Expression.Equal(m, c);
            Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(b, e);
            return lambda;
        }
 
        protected abstract string GetPrimaryKeyPropertyName<T>();
        public abstract T Get<T>(object id) where T : class;
        public abstract IQueryable<T> List<T>() where T : class;
        public abstract void Insert<T>(T entity) where T : class;
        public abstract void Update<T>(T entity) where T : class;
        public abstract void Delete<T>(T entity) where T : class;
    }
}

The third step was to create a class named DbEntityRepository.  This class inherits from the ARepository class by overriding the abstract methods with IQToolKit Data Provider specific code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using IQToolkit;
using IQToolkit.Data.Common;
 
namespace IQToolkitContrib {
    public class DbEntityRepository : ARepository {
        public DbEntityProviderBase Provider { get; private set; }
 
        public DbEntityRepository(DbEntityProviderBase provider) {
            this.Provider = provider;
        }
 
        protected override string GetPrimaryKeyPropertyName<T>() {
            MappingEntity mappingEntity = this.Provider.Mapping.GetEntity(typeof(T));
            List<MemberInfo> memberInfoList = this.Provider.Mapping.GetPrimaryKeyMembers(mappingEntity).ToList();
 
            if (memberInfoList.Count != 1) {
                throw new ApplicationException(string.Format("Cannot determine the primary key for {0}", typeof(T)));
            }
 
            MemberInfo primaryKeyMemberInfo = memberInfoList[0];
            return primaryKeyMemberInfo.Name;
        }
 
        public override T Get<T>(object id) {
            //// The "FirstOrDefault" will not work with LINQtoVFP.  The following statement would cause an error because it does not include an OrderBy.
            //// return this.List<T>().FirstOrDefault(this.CreateGetExpression<T>(id, primaryKeyMemberInfo.Name));   
 
            List<T> list = this.List<T>().Where<T>(this.CreateGetExpression<T>(id)).ToList();
 
            if (list.Count == 0) {
                return default(T);
            }
 
            return list[0];
        }
        
        public override IQueryable<T> List<T>() {
            return this.GetEntityTable<T>();
        }
 
        public override void Insert<T>(T entity) {
            if (entity is IValidate) {
                ((IValidate)entity).Validate();
            }
 
            this.GetEntityTable<T>().Insert<T>(entity);
        }
        
        public override void Update<T>(T entity) {
            if (entity is IValidate) {
                ((IValidate)entity).Validate();
            }
 
            this.GetEntityTable<T>().Update<T>(entity);
        }
 
        public override void Delete<T>(T entity) {
            this.GetEntityTable<T>().Delete<T>(entity);
        }
 
        private IEntityTable<T> GetEntityTable<T>() {
            return this.Provider.GetTable<T>(this.Provider.Mapping.GetTableId(typeof(T)));
        }
    }
}


At this point, I have developed a very simple Repository to work with the IQToolKit Providers.  This Repository in itself has a few uses but I believe that it would be more useful (at lease for the purpose of TDD) if I added one more layer of abstraction.

So for the fourth step, I created class named DataContext.  This class implements the IRepository interface and has a constructor that is passed an IRepository Instance.  The purpose of this class is to simply wrap up the calls to the IRepository Instance.

(It helps to think of the IRepository Instance as the Data Access Layer and the DataContext as the Business Logic Layer.)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IQToolkitContrib {
    public class DataContext : IRepository {
        private IRepository repository;
        
        public DataContext(IRepository repository) {
            this.repository = repository;
        }
 
        public T Get<T>(object id) where T : class {
            return this.repository.Get<T>(id);
        }
 
        public IQueryable<T> List<T>() where T : class {
            return this.repository.List<T>();
        }
 
        public void Insert<T>(T entity) where T : class {
            this.repository.Insert<T>(entity);
        }
 
        public void Update<T>(T entity) where T : class {
            this.repository.Update<T>(entity);
        }
 
        public void Delete<T>(T entity) where T : class {
            this.repository.Delete<T>(entity);
        }
    }
}

In the final step, I created a class named MemoryRepository.  This class inherits from the ARepository class by overriding the abstract methods to work with a List<object> Instance.  This class can be used to pass into the DataContext while creating tests using TDD.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
 
namespace IQToolkitContrib {
    public partial class MemoryRepository : ARepository {
        private List<object> entities = new List<object>();
 
        protected override string GetPrimaryKeyPropertyName<T>() {
            return Path.GetExtension(typeof(T).FullName).Substring(1) + "Id";
        }
 
        protected virtual void SetIdentityValue<T>(T entity) where T : class {
            PropertyInfo pi = typeof(T).GetProperty(this.GetPrimaryKeyPropertyName<T>());
 
            switch (pi.PropertyType.FullName) {
                case "System.Int32":
                case "System.Int64":
                    long id = Convert.ToInt64(pi.GetValue(entity, null));
 
                    if (id <= 0) {
                        pi.SetValue(entity, this.List<T>().Count() + 1, null);
                    }
 
                    break;
                case "System.String":
                    if (string.IsNullOrEmpty(pi.GetValue(entity, null) as string)) {
                        pi.SetValue(entity, (this.List<T>().Count() + 1).ToString(), null);
                    }
 
                    break;
                case "System.Guid":
                    Guid guidId = (Guid)pi.GetValue(entity, null);
 
                    if (guidId == default(Guid)) {
                        pi.SetValue(entity, Guid.NewGuid(), null);
                    }
 
                    break;
                default:
                    throw new NotImplementedException(string.Format("PropertyType {0} not handled.", pi.PropertyType.FullName));
            }
        }
 
        public override T Get<T>(object id) {
            return this.List<T>().FirstOrDefault(this.CreateGetExpression<T>(id));
        }
 
        public override IQueryable<T> List<T>() {
            return this.entities.OfType<T>().AsQueryable();
        }
 
        public override void Insert<T>(T entity) {
            if (entity is IValidate) {
                ((IValidate)entity).Validate();
            }
 
            this.SetIdentityValue<T>(entity);
            this.entities.Add(entity);
        }
 
        public override void Update<T>(T entity) {
            if (entity is IValidate) {
                ((IValidate)entity).Validate();
            }
 
            string primaryKeyPropertyName = this.GetPrimaryKeyPropertyName<T>();
            PropertyInfo pi = typeof(T).GetProperty(primaryKeyPropertyName);
            object id = pi.GetValue(entity, null);
            T originalEntity = this.Get<T>(id);
 
            var properties = typeof(T).GetProperties();
 
            foreach (var prop in properties) {
                if (prop.CanWrite && prop.Name != primaryKeyPropertyName) {
                    var value = prop.GetValue(entity, null);
                    prop.SetValue(originalEntity, value, null);
                }
            }
        }
 
        public override void Delete<T>(T entity) {
            this.entities.Remove(entity);
        }
    }
}


Source Code and Binaries can be found at IQToolkit Contrib.

August 23, 2009

Custom LinqDataSource for IQToolkit

Filed under: Development — Tags: , — Tom Brothers @ 1:34 am

I was trying to work though a LINQ to SQL example using IQToolkit as the data context. I found that the LinqDataSource would work fine for reading the data.  But when attempting to update the data an exception was raised indicating the data context did not extent System.Data.Linq.DataContext.  So to finish up the example, I needed to create a custom LinqDataSource for IQToolkit.  After a little inspection using Reflector, I found that I just needed to create two sub-classes.

The first class that needed to be created was a sub-class of LinqDataSourceView:

using System;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using IQToolkit;
 
namespace IQToolkitContrib.Web {
    public class DataSourceView : LinqDataSourceView {
        private LinqDataSource owner;
 
        public DataSourceView(LinqDataSource owner, string name, HttpContext context)
            : base(owner, name, context) {
            this.owner = owner;
        }
 
        /// <summary>
        /// Make sure that the data context has a property that implements IEntityTable
        /// </summary>
        protected override void ValidateContextType(Type contextType, bool selecting) {
            if (!selecting && contextType.GetProperties().Where(p => p.PropertyType.GetInterface("IEntityTable") != null).Count() == 0) {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The data context used by IQToolkit-DataSourceView '{0}' must have an IEntityTable Property when the Delete, Insert or Update operations are enabled.", this.owner.ID));
            }
        }
 
        /// <summary>
        /// Make sure that the table implementes IEntityTable
        /// </summary>
        protected override void ValidateTableType(Type tableType, bool selecting) {
            if (!selecting && (!tableType.IsGenericType || tableType.GetInterface("IEntityTable") == null)) {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The table property used by IQToolkit-DataSourceView '{0}' must extend IEntityTable when the Delete, Insert or Update operations are enabled.", this.owner.ID));
            }
        }
 
        protected override void DeleteDataObject(object dataContext, object table, object oldDataObject) {
            ((IEntityTable)table).Delete(oldDataObject);
        }
 
        protected override void UpdateDataObject(object dataContext, object table, object oldDataObject, object newDataObject) {
            ((IEntityTable)table).Update(newDataObject);
        }
 
        protected override void InsertDataObject(object dataContext, object table, object newDataObject) {
            ((IEntityTable)table).Insert(newDataObject);
        }
    }
}

The second class that needed to be created was a sub-class of LinqDataSource:

using System.Web.UI.WebControls;
 
namespace IQToolkitContrib.Web {
    public class DataSource : LinqDataSource {
        protected override LinqDataSourceView CreateView() {
            return new DataSourceView(this, "DefaultView", this.Context);
        }
    }
}

After building these two classes in a separate assembly, I was able to use the DataSource as I would any other custom server control.

Blog at WordPress.com.