Which table can a ForeignKeyConstraint be placed on???

G

greg r

Ok,
Here is a basic obvious question NO one answers:

Why do some articles show the ForeignKeyConstraint being places on the
Parent table, and others show it being added to the Child table?

Does it matter? Since both the child and parent tables and columns
are stored in it, why do I have to put it in a specific table
anyway???

As well...if this is the case what is the point of the DataRelation?

A ForeignKeyConstraint should be able to perform the exact same goal,
if it was stored outside a given table.

This really seems illogical...any help???
 
G

greg r

Actually, I have read all those documents..and they don't answer my
basic question about foreign keys!

In fact, they contradict several pieces of example code in the MSDN.
(I was expecting this snap answer)

Here is the question again:
- Suppose a DataRelation is NOT being used anywhere (forget the
DataRelation!)
- Suppose a ForeignKeyConstraint is created on parent table A and
child table B

Question: Does it matter which table (A or B) the ForeignKeyConstraint
is
added to?

(Its a very simple question...draw it on paper if you don't understand
it)

Ive seen samples where sometimes they add it to A, and sometimes
B...WITHOUT ANY explanation.

I don't see any reason its added it ANY table because it has both
tables and their columns stored inside the ForeignKey!

Its funny how people don't really explain this properly.
 
T

Teemu Keiski

Hello,

***
(Its a very simple question...draw it on paper if you don't understand it)
***

And with this type of comments you definitely won't get answers... ;-)

***
The other part
***

Yes, the ForeignKeyConstraint does take references to the DataColumns and
the Table and store them internally, but enforcing the constraint does not
start from the constraint but from the update, insert, delete etc operation
.. So if you don't add the constraint to the Constraints collection (of
either table) it is now known when constrains are checked. i.e the
constraint has correct references but the operation that uses the constraint
to check stuff isn't aware of constraint's existence.

Take an example. This code happens when row is changing in DataTable:

**
enumerator1 = this.Constraints.GetEnumerator();
try
{
while (enumerator1.MoveNext())
{
constraint1 = ((Constraint) enumerator1.Current);
constraint1.CheckConstraint(row1, action1);
}
}
**
You clearly see that Constraints collection is referenced to get to check
the constrains. If constraint does not exist there, it is hard to ensure it.

Ok then another example, consider the code:

***
//Create the DataSet
DataSet ds=new DataSet();

//First table
DataTable dt1=new DataTable();
ds.Tables.Add(dt1);
dt1.Columns.Add("ID",typeof(int));
dt1.Columns.Add("text",typeof(string));

//Second table
DataTable dt2=new DataTable();
ds.Tables.Add(dt2);
dt2.Columns.Add("ID",typeof(int));
dt2.Columns.Add("ForeignID",typeof(int));

ForeignKeyConstraint cons=new
ForeignKeyConstraint("const",dt1.Columns["ID"],dt2.Columns["ForeignID"]);

//Add constraint to the table
dt2.Constraints.Add(cons) ;

//Create parent row
DataRow row=dt1.NewRow();
row[0]=1;
row[1]="something";
dt1.Rows.Add(row);

//Try to create child row with false data
row=dt2.NewRow();
row[0]=1;
//This breaks with the constraint
row[1]=2;
dt2.Rows.Add(row);
***

If you run it as is, you'll get exception:
"ForeignKeyConstraint const requires the child key values (2) to exist in
the parent table" because value 2 I try to add to the second table as
foreign key does not exists in the parent table. This is clear, OK.

1. Now change the code so that comment the line
//Add constraint to the table
//dt2.Constraints.Add(cons) ;

i.e constraint is not anymore added to any table

--> No exception is raised, means constraint is not ensured because it
doesn't exist in Constrains collection, even though it does reference the
parent/child columns but internally. This goes to the first set of code,
constraint is not in Constrains collection.

2. Change the same code but add the constraint to Table dt1:

//Add constraint to the table
dt1.Constraints.Add(cons) ;

Run the code--> You'll get exception: "This constraint cannot be added since
ForeignKey doesn't belong to table Table1". This means ForeignKeyConstraint
can only be added to the child table.

The internal reason for this is ForeignKeyConstraints internal method: which
is called when ForeignKeyConstraint is added to the collection.

***
internal override void CheckCanAddToCollection(ConstraintCollection
constraints)
{ if (base.Table != constraints.Table)
{
throw ExceptionBuilder.ConstraintAddFailed(constraints.Table);

}
}
***

Basically it means that ForeignKeyConstraint must be added to the child
table (as was clear after checking the previous code) as I said before4.
That check does it clearly that the Table the constraint references must be
same as the Constraints collection it is added to. More clearly the Table
property of the ForeignKeyConstraint returns the table like this:

return this.childKey.Table;

Which even more clearly indicates that constraint must be in child key's
table.

Is there anything more I can do for you?

--
Teemu Keiski
MCP, Microsoft MVP (ASP.NET), AspInsiders member
ASP.NET Forum Moderator, AspAlliance Columnist
 
T

Teemu Keiski

And to add, after I checked some examples in MSDN, there definitely were
inconsistencies.Like the example for :
DataTable.Constraints Property

private void CreateConstraint(DataSet myDataSet, string table1, string
table2, string column1, string column2)
{
ForeignKeyConstraint idKeyRestraint = new
ForeignKeyConstraint(myDataSet.Tables[table1].Columns[column1],

myDataSet.Tables[table2].Columns[column2]);
// Set null values when a value is deleted.
idKeyRestraint.DeleteRule = Rule.SetNull;
idKeyRestraint.UpdateRule = Rule.Cascade;
// Set AcceptRejectRule to cascade changes.
idKeyRestraint.AcceptRejectRule = AcceptRejectRule.Cascade;

myDataSet.Tables[table1].Constraints.Add(idKeyRestraint);
myDataSet.EnforceConstraints = true;
}

This code fails if you apply it to the scenario I posted. It gives the same
exception:
"This constraint cannot be added since ForeignKey doesn't belong to table
Table1".

By changing the code to:

myDataSet.Tables[table2].Constraints.Add(idKeyRestraint);

makes it to work.


--
Teemu Keiski
MCP, Microsoft MVP (ASP.NET), AspInsiders member
ASP.NET Forum Moderator, AspAlliance Columnist



Teemu Keiski said:
Hello,

***
(Its a very simple question...draw it on paper if you don't understand it)
***

And with this type of comments you definitely won't get answers... ;-)

***
The other part
***

Yes, the ForeignKeyConstraint does take references to the DataColumns and
the Table and store them internally, but enforcing the constraint does not
start from the constraint but from the update, insert, delete etc operation
. So if you don't add the constraint to the Constraints collection (of
either table) it is now known when constrains are checked. i.e the
constraint has correct references but the operation that uses the constraint
to check stuff isn't aware of constraint's existence.

Take an example. This code happens when row is changing in DataTable:

**
enumerator1 = this.Constraints.GetEnumerator();
try
{
while (enumerator1.MoveNext())
{
constraint1 = ((Constraint) enumerator1.Current);
constraint1.CheckConstraint(row1, action1);
}
}
**
You clearly see that Constraints collection is referenced to get to check
the constrains. If constraint does not exist there, it is hard to ensure it.

Ok then another example, consider the code:

***
//Create the DataSet
DataSet ds=new DataSet();

//First table
DataTable dt1=new DataTable();
ds.Tables.Add(dt1);
dt1.Columns.Add("ID",typeof(int));
dt1.Columns.Add("text",typeof(string));

//Second table
DataTable dt2=new DataTable();
ds.Tables.Add(dt2);
dt2.Columns.Add("ID",typeof(int));
dt2.Columns.Add("ForeignID",typeof(int));

ForeignKeyConstraint cons=new
ForeignKeyConstraint("const",dt1.Columns["ID"],dt2.Columns["ForeignID"]);

//Add constraint to the table
dt2.Constraints.Add(cons) ;

//Create parent row
DataRow row=dt1.NewRow();
row[0]=1;
row[1]="something";
dt1.Rows.Add(row);

//Try to create child row with false data
row=dt2.NewRow();
row[0]=1;
//This breaks with the constraint
row[1]=2;
dt2.Rows.Add(row);
***

If you run it as is, you'll get exception:
"ForeignKeyConstraint const requires the child key values (2) to exist in
the parent table" because value 2 I try to add to the second table as
foreign key does not exists in the parent table. This is clear, OK.

1. Now change the code so that comment the line
//Add constraint to the table
//dt2.Constraints.Add(cons) ;

i.e constraint is not anymore added to any table

--> No exception is raised, means constraint is not ensured because it
doesn't exist in Constrains collection, even though it does reference the
parent/child columns but internally. This goes to the first set of code,
constraint is not in Constrains collection.

2. Change the same code but add the constraint to Table dt1:

//Add constraint to the table
dt1.Constraints.Add(cons) ;

Run the code--> You'll get exception: "This constraint cannot be added since
ForeignKey doesn't belong to table Table1". This means ForeignKeyConstraint
can only be added to the child table.

The internal reason for this is ForeignKeyConstraints internal method: which
is called when ForeignKeyConstraint is added to the collection.

***
internal override void CheckCanAddToCollection(ConstraintCollection
constraints)
{ if (base.Table != constraints.Table)
{
throw ExceptionBuilder.ConstraintAddFailed(constraints.Table);

}
}
***

Basically it means that ForeignKeyConstraint must be added to the child
table (as was clear after checking the previous code) as I said before4.
That check does it clearly that the Table the constraint references must be
same as the Constraints collection it is added to. More clearly the Table
property of the ForeignKeyConstraint returns the table like this:

return this.childKey.Table;

Which even more clearly indicates that constraint must be in child key's
table.

Is there anything more I can do for you?

--
Teemu Keiski
MCP, Microsoft MVP (ASP.NET), AspInsiders member
ASP.NET Forum Moderator, AspAlliance Columnist












greg r said:
Actually, I have read all those documents..and they don't answer my
basic question about foreign keys!

In fact, they contradict several pieces of example code in the MSDN.
(I was expecting this snap answer)

Here is the question again:
- Suppose a DataRelation is NOT being used anywhere (forget the
DataRelation!)
- Suppose a ForeignKeyConstraint is created on parent table A and
child table B

Question: Does it matter which table (A or B) the ForeignKeyConstraint
is
added to?

(Its a very simple question...draw it on paper if you don't understand
it)

Ive seen samples where sometimes they add it to A, and sometimes
B...WITHOUT ANY explanation.

I don't see any reason its added it ANY table because it has both
tables and their columns stored inside the ForeignKey!

Its funny how people don't really explain this properly.










"Teemu Keiski" <[email protected]> wrote in message
http://msdn.microsoft.com/library/d...l/cpconaddingrelationshipbetweentwotables.asp UniqueConstraint
http://msdn.microsoft.com/library/d...uide/html/cpconaddingconstraintstodataset.asp
 
G

greg r

Teemu,
Thank you very much. You answered the question I was looking for.
I am sorry I sounded snappy, I was just frustrated.

However, there is still another question regarding this.

A ForeignKeyConstraint actually should apply to an update on a Parent
table as well. For example in a "cascade" deletion, deleting a parent
record will delete the children. So I still don't see the point of
putting it on the child. It "must" be there, the parent has to know
about it anyway becuse it gets triggered on a cascading deletion
initiated from the parent.

Again, this goes back to my argument that conceptually, it should make
not any difference whether it goes on the parent or on the child. The
ConstraintCollection should be at the level of the DataSet not the
DataTable. Thats what my logic says *should* be the case, but I only
have a limited understanding of how this works.

----------------
What bothers me is that Microsoft have people paid big bucks to get
this information correct. In fact, some of those articles are written
by consultants who portray themselves as experts. Im not even an
expert and I can pick out obvious errors like this.

Here is a clear example:

The article "DataRelations and Relatives" by "Dino Esposito of
"Wintellect" from the MSDN. He goes on and on about this, and I bet
he never even actually tried to run his own sample code (= sloppy)
-----------------------
"So, if you're going to create an in-memory relation for cached,
disconnected data that you plan to modify, make sure you first define
a ForeignKeyConstraint object on the parent table. This ensures that
any change that could affect the related tables is properly managed.
You create a constraint like this:

ForeignKeyConstraint fkc;
DataColumn dcCustomersCustID, dcOrdersCustID;
// Get columns and create the constraint
dcCustomersCustID = DataSet1.Tables["Customers"].Columns["CustID"];
dcCustomersCustID = DataSet1.Tables["Orders"].Columns["CustID"];
fkc = new ForeignKeyConstraint("CustomersFK",
dcCustomersCustID, dcOrdersCustID);
// Shape up the constraint for delete and update
fkc.DeleteRule = Rule.SetNull;
fkc.UpdateRule = Rule.Cascade;

A ForeignKeyConstraint is created on the parent table using the common
column that the parent and child table share. To specify how a child
table behaves whenever a row on the parent table is deleted or
updated, you use the DeleteRule and UpdateRule fields. In this case, I
set all the values on the child row to NULL when the corresponding
parent row is deleted. Furthermore, any update simply trickles down
from the parent row to the child row.

A DataTable object maintains its collection of ForeignKeyConstraint
objects in a ConstraintCollection class that is accessible through the
DataTable's Constraints property. As a final note, bear in mind that
constraints are not enforced on tables if you set the
EnforceConstraints property to false.

// Add the constraint and enforce it
DataSet1.Tables["Customers"].Constraints.Add(fkc);
DataSet1.EnforceConstraints = true;
"
 
T

Teemu Keiski

Haha, no problem, I see,

***
// Get columns and create the constraint
dcCustomersCustID = DataSet1.Tables["Customers"].Columns["CustID"];
dcCustomersCustID = DataSet1.Tables["Orders"].Columns["CustID"];

fkc = new ForeignKeyConstraint("CustomersFK",
dcCustomersCustID, dcOrdersCustID);
// Shape up the constraint for delete and update
***
There is the column variable as well referenced, though that must be just a
typo. Esposito should know damn well what he is doing, though the code I
tested with speaks its own language though there mightr be other things I
could have not taken into account.

I'll experiment more with this and get back to you.

--
Teemu Keiski
MCP, Microsoft MVP (ASP.NET), AspInsiders member
ASP.NET Forum Moderator, AspAlliance Columnist




greg r said:
Teemu,
Thank you very much. You answered the question I was looking for.
I am sorry I sounded snappy, I was just frustrated.

However, there is still another question regarding this.

A ForeignKeyConstraint actually should apply to an update on a Parent
table as well. For example in a "cascade" deletion, deleting a parent
record will delete the children. So I still don't see the point of
putting it on the child. It "must" be there, the parent has to know
about it anyway becuse it gets triggered on a cascading deletion
initiated from the parent.

Again, this goes back to my argument that conceptually, it should make
not any difference whether it goes on the parent or on the child. The
ConstraintCollection should be at the level of the DataSet not the
DataTable. Thats what my logic says *should* be the case, but I only
have a limited understanding of how this works.

----------------
What bothers me is that Microsoft have people paid big bucks to get
this information correct. In fact, some of those articles are written
by consultants who portray themselves as experts. Im not even an
expert and I can pick out obvious errors like this.

Here is a clear example:

The article "DataRelations and Relatives" by "Dino Esposito of
"Wintellect" from the MSDN. He goes on and on about this, and I bet
he never even actually tried to run his own sample code (= sloppy)
-----------------------
"So, if you're going to create an in-memory relation for cached,
disconnected data that you plan to modify, make sure you first define
a ForeignKeyConstraint object on the parent table. This ensures that
any change that could affect the related tables is properly managed.
You create a constraint like this:

ForeignKeyConstraint fkc;
DataColumn dcCustomersCustID, dcOrdersCustID;
// Get columns and create the constraint
dcCustomersCustID = DataSet1.Tables["Customers"].Columns["CustID"];
dcCustomersCustID = DataSet1.Tables["Orders"].Columns["CustID"];
fkc = new ForeignKeyConstraint("CustomersFK",
dcCustomersCustID, dcOrdersCustID);
// Shape up the constraint for delete and update
fkc.DeleteRule = Rule.SetNull;
fkc.UpdateRule = Rule.Cascade;

A ForeignKeyConstraint is created on the parent table using the common
column that the parent and child table share. To specify how a child
table behaves whenever a row on the parent table is deleted or
updated, you use the DeleteRule and UpdateRule fields. In this case, I
set all the values on the child row to NULL when the corresponding
parent row is deleted. Furthermore, any update simply trickles down
from the parent row to the child row.

A DataTable object maintains its collection of ForeignKeyConstraint
objects in a ConstraintCollection class that is accessible through the
DataTable's Constraints property. As a final note, bear in mind that
constraints are not enforced on tables if you set the
EnforceConstraints property to false.

// Add the constraint and enforce it
DataSet1.Tables["Customers"].Constraints.Add(fkc);
DataSet1.EnforceConstraints = true;
"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top