Re: Child Aggregate Filter Not Recognising Newly Added Child Rows (ADO.NET 2.0 Dataset) by Simon
Simon
Tue Mar 20 11:41:07 CDT 2007
After a bit more digging around I believe I have found the core of the
problem:
1) *IF* the Parent Row's Rowstate is 'UnChanged' then, any Aggregate
Functions referencing Child Rows actually work off the Original Field
Values (IMO this is rather unexpected behaviour). That is, EXCEPT
'Deleted' Rows, which are correctly ignored. As I've mentioned before,
Added Rows are also (IMO) incorrectly ignored, presumably as they have
no Original Field Values.
2) However, when the Parent Row's Rowstate is either 'Added' or
'Modified', then the Aggregate Functions correctly work off the
Modified/Current Child Field Values.
3) This behaviour seems to occur in both the .Compute and .Select
DataTable Methods, HOWEVER, Expression columns seem to always
correctly reference the Current Child Row values (irrespective of the
Parent Row's RowState).
This seems rather inconsistent behaviour to me, and I would expect
that the correct behaviour for these methods would be that the
Aggregate Functions should always work off the Current Child Values
(like it does for an Expression Column) Although I don't consider
using Expression Columns a work around to this, as they suffer from
some other very well documented problems!
I would appreciate any comments/feedback from anybody who maybe has
been working with this in the past, or even has a different view on
what the correct behaviour for these methods should be?
I've not seen any specific documentation highlighting this behaviour
(or reasons for it), and I'm surprised this exists in such a
fundamental component of the (.NET 2.0) dataset object, maybe somebody
could point me in the right direction for this?
Here is some more specific example code to highlight the problem
exactly:
[code]
Public Class Form1
'
==================================================================
' Form Requires:
' - 3 Labels (Label1, Label2, Label3)
' - 1 Button (Button1)Public Class Form1
'
==================================================================
' Form Requires:
' - 3 Labels (Label1, Label2, Label3)
' - 1 Button (Button1)
' - 1 UnTypes Dataset (SataSet1)
'
==================================================================
Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
DataSet1 = SetupTableSchema()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
DataSet1.Clear()
FillParent()
'
==================================================================
' Use Select To Count The Number Of Parent Rows That
Correctly
' Match 3 Children In An Aggregate Filter
'
' Performing a This Should Return 3, as all Parents have 3
Children
' - However, It incorrectly returns 2
'
==================================================================
Label1.Text =
DataSet1.Tables("Parent").Select("COUNT(CHILD(FK_Parent_Child).
[RowState]) = 3").GetLength(0)
Dim iChildRowStates As Int32
'
==================================================================
' Now Use Compute To SUM The Parent RowState Values (BitMask)
For
' Rows Whose Child Aggregate Filter SUM Matches
iChildRowStates
'
==================================================================
'
==================================================================
' Which Parent Row Rowstates Match Correctly SUM All Three
Child
' Rowstates: Added, Modified, UnChanged? (Deletes Should Be
Ignored)
' - Expected Answer: 22 (UnChanged - 2, Added - 4, Modified
- 16)
' - Actual Answer: 20 (Added - 4, Modified - 16)
'
==================================================================
iChildRowStates = DataRowState.Unchanged Or
DataRowState.Modified Or DataRowState.Added
Label2.Text =
DataSet1.Tables("Parent").Compute("SUM([RowState])",
String.Format("SUM(CHILD(FK_Parent_Child).[RowState]) = {0}",
iChildRowStates)).ToString()
'
==================================================================
' UnChanged Parent Rows ONLY Filter The SUM Of UnChanged Child
Rows
' (And Original Values Of Modified Child Rows)
' - i.e. This following returns: 2 (UnChanged)
' - However, it's not all Original Values, as Deleted Row
Original
' Values Are Correctly Ignored
'
==================================================================
iChildRowStates = DataRowState.Unchanged
Label3.Text =
DataSet1.Tables("Parent").Compute("SUM([RowState])",
String.Format("SUM(CHILD(FK_Parent_Child).[RowState]) = {0}",
iChildRowStates)).ToString()
End Sub
Public Sub FillParent()
' ==================================================
' Add Three Rows To The Parent Table With Different
' Rowstates (Added, UnChanged, Modified)
' (Storing Their RowState Enum In A Separate Field)
' ==================================================
With DataSet1.Tables("Parent").Rows.Add(New Object() {Nothing,
DataRowState.Added})
FillChildren(.Item("ID"))
End With
With DataSet1.Tables("Parent").Rows.Add(New Object() {Nothing,
DataRowState.Unchanged})
FillChildren(.Item("ID"))
.AcceptChanges()
End With
With DataSet1.Tables("Parent").Rows.Add(New Object() {Nothing,
0})
FillChildren(.Item("ID"))
.AcceptChanges()
.Item("RowState") = DataRowState.Modified
End With
End Sub
Public Sub FillChildren(ByVal iParentID As Int32)
' ==================================================
' Add For Rows To The Child Table With All Four
' Rowstates (Added, UnChanged, Modified, Deleted)
' (Storing Their RowState Enum In A Separate Field)
' - This is done for each Parent Row
' ==================================================
DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, DataRowState.Added})
With DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, DataRowState.Unchanged})
.AcceptChanges()
End With
With DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, 0})
.AcceptChanges()
.Item("RowState") = DataRowState.Modified
End With
With DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, DataRowState.Deleted})
.AcceptChanges()
.Delete()
End With
End Sub
Public Function SetupTableSchema() As DataSet
Dim ds As New DataSet
Dim oParent As DataTable = ds.Tables.Add("Parent")
Dim oChild As DataTable = ds.Tables.Add("Child")
' ==================================================
' Set Up Parent Table
' ==================================================
With oParent
With .Columns.Add("ID", GetType(System.Int32))
.AutoIncrement = True
.AllowDBNull = False
.ReadOnly = True
End With
.PrimaryKey = New DataColumn() {.Columns("ID")}
.Columns.Add("RowState", GetType(System.Int32))
End With
' ==================================================
' Set Up Child Table
' ==================================================
With oChild
With .Columns.Add("ID", GetType(System.Int32))
.AutoIncrement = True
.AllowDBNull = False
.ReadOnly = True
End With
.PrimaryKey = New DataColumn() {.Columns("ID")}
.Columns.Add("ParentID", GetType(System.Int32))
.Columns.Add("RowState", GetType(System.Int32))
End With
' ==================================================
' Create Relationship
' ==================================================
ds.Relations.Add("FK_Parent_Child", oParent.Columns("ID"),
oChild.Columns("ParentID"), True)
Return ds
End Function
End Class
' - 1 UnTypes Dataset (SataSet1)
'
==================================================================
Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
DataSet1 = SetupTableSchema()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
DataSet1.Clear()
FillParent()
'
==================================================================
' Use Select To Count The Number Of Parent Rows That
Correctly
' Match 3 Children In An Aggregate Filter
'
' Performing a This Should Return 3, as all Parents have 3
Children
' - However, It incorrectly returns 2
'
==================================================================
Label1.Text =
DataSet1.Tables("Parent").Select("COUNT(CHILD(FK_Parent_Child).
[RowState]) = 3").GetLength(0)
Dim iChildRowStates As Int32
'
==================================================================
' Now Use Compute To SUM The Parent RowState Values (BitMask)
For
' Rows Whose Child Aggregate Filter SUM Matches
iChildRowStates
'
==================================================================
'
==================================================================
' Which Parent Row Rowstates Match Correctly SUM All Three
Child
' Rowstates: Added, Modified, UnChanged? (Deletes Should Be
Ignored)
' - Expected Answer: 22 (UnChanged - 2, Added - 4, Modified
- 16)
' - Actual Answer: 20 (Added - 4, Modified - 16)
'
==================================================================
iChildRowStates = DataRowState.Unchanged Or
DataRowState.Modified Or DataRowState.Added
Label2.Text =
DataSet1.Tables("Parent").Compute("SUM([RowState])",
String.Format("SUM(CHILD(FK_Parent_Child).[RowState]) = {0}",
iChildRowStates)).ToString()
'
==================================================================
' UnChanged Parent Rows ONLY Filter The SUM Of UnChanged Child
Rows
' (And Original Values Of Modified Child Rows)
' - i.e. This following returns: 2 (UnChanged)
' - However, it's not all Original Values, as Deleted Row
Original
' Values Are Correctly Ignored
'
==================================================================
iChildRowStates = DataRowState.Unchanged
Label3.Text =
DataSet1.Tables("Parent").Compute("SUM([RowState])",
String.Format("SUM(CHILD(FK_Parent_Child).[RowState]) = {0}",
iChildRowStates)).ToString()
End Sub
Public Sub FillParent()
' ==================================================
' Add Three Rows To The Parent Table With Different
' Rowstates (Added, UnChanged, Modified)
' (Storing Their RowState Enum In A Separate Field)
' ==================================================
With DataSet1.Tables("Parent").Rows.Add(New Object() {Nothing,
DataRowState.Added})
FillChildren(.Item("ID"))
End With
With DataSet1.Tables("Parent").Rows.Add(New Object() {Nothing,
DataRowState.Unchanged})
FillChildren(.Item("ID"))
.AcceptChanges()
End With
With DataSet1.Tables("Parent").Rows.Add(New Object() {Nothing,
0})
FillChildren(.Item("ID"))
.AcceptChanges()
.Item("RowState") = DataRowState.Modified
End With
End Sub
Public Sub FillChildren(ByVal iParentID As Int32)
' ==================================================
' Add For Rows To The Child Table With All Four
' Rowstates (Added, UnChanged, Modified, Deleted)
' (Storing Their RowState Enum In A Separate Field)
' - This is done for each Parent Row
' ==================================================
DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, DataRowState.Added})
With DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, DataRowState.Unchanged})
.AcceptChanges()
End With
With DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, 0})
.AcceptChanges()
.Item("RowState") = DataRowState.Modified
End With
With DataSet1.Tables("Child").Rows.Add(New Object() {Nothing,
iParentID, DataRowState.Deleted})
.AcceptChanges()
.Delete()
End With
End Sub
Public Function SetupTableSchema() As DataSet
Dim ds As New DataSet
Dim oParent As DataTable = ds.Tables.Add("Parent")
Dim oChild As DataTable = ds.Tables.Add("Child")
' ==================================================
' Set Up Parent Table
' ==================================================
With oParent
With .Columns.Add("ID", GetType(System.Int32))
.AutoIncrement = True
.AllowDBNull = False
.ReadOnly = True
End With
.PrimaryKey = New DataColumn() {.Columns("ID")}
.Columns.Add("RowState", GetType(System.Int32))
End With
' ==================================================
' Set Up Child Table
' ==================================================
With oChild
With .Columns.Add("ID", GetType(System.Int32))
.AutoIncrement = True
.AllowDBNull = False
.ReadOnly = True
End With
.PrimaryKey = New DataColumn() {.Columns("ID")}
.Columns.Add("ParentID", GetType(System.Int32))
.Columns.Add("RowState", GetType(System.Int32))
End With
' ==================================================
' Create Relationship
' ==================================================
ds.Relations.Add("FK_Parent_Child", oParent.Columns("ID"),
oChild.Columns("ParentID"), True)
Return ds
End Function
End Class
[/code]