Part 1: The Target Code
Classic ADO.NET is the most successful client side database technology in the history of Microsoft. Even if the Entity Framework (officially "ADO.NET Entity Framework") is as successful as Microsoft thinks it will be, ADO.NET DataSets will be around for years.
One of the biggest weaknesses of the ADO.NET DataSet is the turn of the century way it handles nullability. Since Nullable
Target Code
To generate code, I need sample target code, so I know where I am going
DataRow
I plan on wrapping each typed DataRow in my own proxy class:
public class EmployeesRowX { // The wrapped row NorthwindDS.EmployeesRow _row; public EmployeesRowX(NorthwindDS.EmployeesRow row) { _row = row; } // Direct access to the row, if you need something I didn’t implement public NorthwindDS.EmployeesRow Row { get { return _row; } } // … }
For a non-nullable field, I just pass the data back without doing anything fancy:
public string FirstName { get { return _row.FirstName; } set { Row.FirstName = value; } }
For a nullable field, I have to translate ADO.NET the pre-nullable logic (IsXXXNull() & SetXXXNull()) to a modern nullable:
public DateTime? BirthDate { get { if (_row.IsBirthDateNull()) return null; else return _row.BirthDate; } set { if (!value.HasValue) _row.SetBirthDateNull(); else _row.BirthDate = value.Value; } }
DataSet and DataTables
I will wrap the DataSet and DataTables in their own proxies:
public class NorthwindDSX { private NorthwindDS _ds; public NorthwindDSX(NorthwindDS ds) { _ds = ds; } public EmployeesDataTableX Employees { get { return new EmployeesDataTableX(_ds.Employees); } } public NorthwindDS DataSet { get { return _ds; } } } public class EmployeesDataTableX: IEnumerable{ private NorthwindDS.EmployeesDataTable _theTable; public EmployeesDataTableX(NorthwindDS.EmployeesDataTable table) { _theTable = table; } public NorthwindDS.EmployeesDataTable Table { get { return _theTable; } } #region IEnumerable Members public IEnumerator GetEnumerator() { return new EmployeesTableEnum(_theTable); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)this; } #endregion }
DataTable’s IEnumberator<T>
And each Table needs an Enumerator:
public class EmployeesTableEnum : IEnumerator{ private NorthwindDS.EmployeesDataTable _collection; private int curIndex; private EmployeesRowX curBox; public EmployeesTableEnum(NorthwindDS.EmployeesDataTable collection) { _collection = collection; curIndex = -1; curBox = default(EmployeesRowX); } public bool MoveNext() { //Avoids going beyond the end of the collection. if (++curIndex >= _collection.Count) return false; else // Set current EmployeesRowX to next item in collection. curBox = new EmployeesRowX( (NorthwindDS.EmployeesRow)_collection.Rows[curIndex]); return true; } public void Reset() { curIndex = -1; } void IDisposable.Dispose() { } public EmployeesRowX Current { get { return curBox; } } object IEnumerator.Current { get { return Current; } } }
Summing it up
So now that I know where I am going, I can get started at making generating code. The code will change as I work through the process.
Since a Typed DataSet is generated, it is possible to generate a full DataSet with nullable fields; that is a job for Microsoft.
No comments:
Post a Comment