より詳細な制御が必要な場合は、データセットが提供する機能の一部を削除する必要があります。カスケードによって引き起こされるメモリを削減する1つの方法は、単純な「カスケードしない」です。テーブルスキーマを使用して、テーブルIDを手動で更新します。
次に、更新する行を制御したり、任意の時点でAcceptChangesを制御したり、GCの中間更新を強制したり、その他の制御したいものを制御したりできます。
私は、私が何を意味するかを示す簡単なテストシナリオを作成しました。
スキーマ:
<?xml version="1.0"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Planet">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Continent">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="PlanetID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Country">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="ContinentID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="County">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="CountryID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="City">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="CountyID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Street">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="CityID" type="xs:int" minOccurs="0" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="People">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="StreetID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Job">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="PeopleID" type="xs:int" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Pets">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" />
<xs:element name="PeopleID" type="xs:int" minOccurs="0" />
<xs:element name="Name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1">
<xs:selector xpath=".//Planet" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="Continent_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//Continent" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="Country_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//Country" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="County_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//County" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="City_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//City" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="Street_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//Street" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="People_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//People" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="Job_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//Job" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="Pets_Constraint1" msdata:ConstraintName="Constraint1">
<xs:selector xpath=".//Pets" />
<xs:field xpath="ID" />
</xs:unique>
<xs:keyref name="Relation8" refer="People_Constraint1">
<xs:selector xpath=".//Pets" />
<xs:field xpath="PeopleID" />
</xs:keyref>
<xs:keyref name="Relation7" refer="People_Constraint1">
<xs:selector xpath=".//Job" />
<xs:field xpath="PeopleID" />
</xs:keyref>
<xs:keyref name="Relation6" refer="Street_Constraint1">
<xs:selector xpath=".//People" />
<xs:field xpath="StreetID" />
</xs:keyref>
<xs:keyref name="Relation5" refer="City_Constraint1">
<xs:selector xpath=".//Street" />
<xs:field xpath="CityID" />
</xs:keyref>
<xs:keyref name="Relation4" refer="County_Constraint1">
<xs:selector xpath=".//City" />
<xs:field xpath="CountyID" />
</xs:keyref>
<xs:keyref name="Relation3" refer="Country_Constraint1">
<xs:selector xpath=".//County" />
<xs:field xpath="CountryID" />
</xs:keyref>
<xs:keyref name="Relation2" refer="Continent_Constraint1">
<xs:selector xpath=".//Country" />
<xs:field xpath="ContinentID" />
</xs:keyref>
<xs:keyref name="Relation1" refer="Constraint1">
<xs:selector xpath=".//Continent" />
<xs:field xpath="PlanetID" />
</xs:keyref>
</xs:element>
</xs:schema>
そして、テストケースを生成するいくつかのコード
private void CreateRows(Int32 MaxBaseRows, Int32 MaxChildRows)
{
dataSet1.Clear();
Int32 RowCount = 0;
Random R = new Random();
foreach (DataTable DT in dataSet1.Tables)
{
Int32 NewCount = R.Next(1, MaxBaseRows);
foreach (var FK in DT.Constraints.OfType<ForeignKeyConstraint>())
{
NewCount = NewCount * R.Next(1, MaxChildRows);
}
for (int i = 0; i < NewCount; i++)
{
DataRow DR = DT.NewRow();
foreach (DataColumn DC in DT.Columns)
{
if (DC.ColumnName == "ID")
{
DR[DC] = DT.Rows.Count;
}
else if (DC.DataType == typeof(Int32))
{
Boolean ValueSet = false;
foreach (var FK in DT.Constraints.OfType<ForeignKeyConstraint>())
{
if (FK.Columns.Contains(DC))
{
DR[DC] = R.Next(0, FK.RelatedTable.Rows.Count);
ValueSet = true;
}
}
if (!ValueSet)
{
DR[DC] = R.Next(0, 10000);
}
}
else if (DC.DataType == typeof(String))
{
DR[DC] = String.Format("{0}{1}", DT.TableName, DT.Rows.Count);
}
}
DT.Rows.Add(DR);
RowCount++;
}
}
label19.Text = RowCount.ToString();
dataSet1.AcceptChanges();
}
private void UpdateUsingCascade()
{
EnableRelations();
GC.Collect();
long Mem = System.GC.GetTotalMemory(false);
if (dataSet1.Tables["Planet"].Rows.Count > 0)
{
dataSet1.Tables["Planet"].Rows[0]["ID"] = new Random().Next(BaseRowCount, BaseRowCount + 10);
}
Mem = System.GC.GetTotalMemory(false) - Mem;
DataSet ds = dataSet1.GetChanges();
Int32 Changes = ds.Tables.OfType<DataTable>().Sum(DT => DT.Rows.Count);
label19.Text = Changes.ToString();
label21.Text = Mem.ToString();
dataSet1.AcceptChanges();
}
private void UpdateManually()
{
DisableRelations();
GC.Collect();
long Mem = System.GC.GetTotalMemory(false);
DataTable DT = dataSet1.Tables["Planet"];
Int32 ChangeCount = 0;
if (DT.Rows.Count > 0)
{
DataColumn DC = DT.Columns["ID"];
Int32 oldValue = Convert.ToInt32(DT.Rows[0][DC]);
DT.Rows[0][DC] = new Random().Next(BaseRowCount + 20,BaseRowCount + 30);
Int32 newValue = Convert.ToInt32(DT.Rows[0][DC]);
foreach (DataRelation Relation in DT.ChildRelations)
{
if (Relation.ParentColumns.Contains(DC))
{
foreach (DataColumn CC in Relation.ChildColumns)
{
foreach (DataRow DR in Relation.ChildTable.Rows)
{
if (Convert.ToInt32(DR[CC]) == oldValue)
{
DR[CC] = newValue;
ChangeCount++;
dataSet1.AcceptChanges();
GC.Collect();
}
}
}
}
}
}
Mem = System.GC.GetTotalMemory(false) - Mem;
label20.Text = ChangeCount.ToString();
label22.Text = Mem.ToString();
dataSet1.AcceptChanges();
}
private void EnableRelations()
{
dataSet1.EnforceConstraints = true;
foreach (DataRelation Relation in dataSet1.Relations)
{
Relation.ChildKeyConstraint.UpdateRule = Rule.Cascade;
}
}
private void DisableRelations()
{
dataSet1.EnforceConstraints = false;
foreach (DataRelation Relation in dataSet1.Relations)
{
Relation.ChildKeyConstraint.UpdateRule = Rule.None;
}
}