Her et et eksempel.
Først interfacet:
    public interface IDAL
    {
        T1 GetOneT1(int f1);
        IList<T1> GetAllT1();
        IList<T1> GetFilterT1(int? f1, string f2);
    }
Så en implementation med data reader:
    public class DataReaderDAL : IDAL
    {
        private IDbConnection GetConnection()
        {
            DbProviderFactory dbf = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings["Test"].ProviderName);
            IDbConnection con = dbf.CreateConnection();
            con.ConnectionString = ConfigurationManager.ConnectionStrings["Test"].ConnectionString;
            con.Open();
            return con;
        }
        public T1 GetOneT1(int f1)
        {
            using(IDbConnection con = GetConnection())
            {
                string paramprefix = ConfigurationManager.AppSettings["ParamPrefix"];;
                IDbCommand sel = con.CreateCommand();
                sel.CommandText = "SELECT f1,f2 FROM t1 WHERE f1 = " + paramprefix + "f1";
                sel.Connection = con;
                IDbDataParameter p = sel.CreateParameter();
                p.ParameterName = paramprefix + "f1";
                p.DbType = DbType.Int32;
                p.Value = f1;
                sel.Parameters.Add(p);
                using(IDataReader rdr = sel.ExecuteReader())
                {
                    if(rdr.Read())
                    {
                        return new T1 { F1 = (int)rdr["f1"], F2 = (string)rdr["f2"]};
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }
        public IList<T1> GetAllT1()
        {
            IList<T1> res = new List<T1>();
            using(IDbConnection con = GetConnection())
            {
                IDbCommand sel = con.CreateCommand();
                sel.CommandText = "SELECT f1,f2 FROM t1";
                sel.Connection = con;
                using(IDataReader rdr = sel.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        res.Add(new T1 { F1 = (int)rdr["f1"], F2 = (string)rdr["f2"]});
                    }
                }
            }
            return res;
        }
        public IList<T1> GetFilterT1(int? f1, string f2)
        {
            IList<T1> res = new List<T1>();
            using(IDbConnection con = GetConnection())
            {
                string isnull = ConfigurationManager.AppSettings["ISNULL"];
                string paramprefix = ConfigurationManager.AppSettings["ParamPrefix"];;
                IDbCommand sel = con.CreateCommand();
                sel.CommandText = "SELECT f1,f2 FROM t1 WHERE f1=" + isnull + "(" + paramprefix + "f1,f1) AND f2 LIKE " + isnull + "(" + paramprefix + "f2, f2)";
                sel.Connection = con;
                IDbDataParameter p1 = sel.CreateParameter();
                p1.ParameterName = paramprefix + "f1";
                p1.DbType = DbType.Int32;
                p1.Value = f1 != null ? (object)f1 : (object)DBNull.Value;
                sel.Parameters.Add(p1);
                IDbDataParameter p2 = sel.CreateParameter();
                p2.ParameterName = paramprefix + "f2";
                p2.DbType = DbType.String;
                p2.Value = f2 != null ? (object)f2 : (object)DBNull.Value;
                sel.Parameters.Add(p2);
                using(IDataReader rdr = sel.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        res.Add(new T1 { F1 = (int)rdr["f1"], F2 = (string)rdr["f2"]});
                    }
                }
            }
            return res;
        }
    }
Hvis man har mulighed for LINQ, så kan ihvertfald så simple queries laves langt nemmere med LINQ.
En implementation med LINQ til Entity Framework:
    public class LINQtoEFDAL : IDAL
    {
        public T1 GetOneT1(int f1)
        {
            using(TestContext ctx = new TestContext())
            {
                return ctx.T1.Where(t1 => t1.F1==f1).First();
            }
        }
        public IList<T1> GetAllT1()
        {
            using(TestContext ctx = new TestContext())
            {
                return ctx.T1.ToList();
            }
        }
        public IList<T1> GetFilterT1(int? f1, string f2)
        {
            using(TestContext ctx = new TestContext())
            {
                return ctx.T1.Where(t1 => (f1==null || t1.F1==f1) && (f2==null || t1.F2.Contains(f2))).ToList();
            }
        }
    }
I eksemplet med data reader er T1 klassen håndskrevet:
    public class T1
    {
        public int F1 { get; set; }
        public string F2 { get; set; }
    }
I eksemplet med LINQ til EF er T1 klassen genereret.
Det sidste re naturligvis noget roderi, men det skulle så være fixet i .NET 4.0 som udkommer om nogle få måneder.