问题
I ' am copying data from table A to table B. Table B has a nullable column that has a default constraint value of 0. In general I set values of columns using the following accessor.
public object this[string columnName]
{
get { return DataTable.Rows[CurrentRow][columnName]; }
set { DataTable.Rows[CurrentRow][columnName] = value; }
}
But I do NOT set my nullable column X.
When I insert the whole row, the default value is not used. Instead of 0, NULL was inserted for the nullable column.
_sqlCommandBuilder = new SqlCommandBuilder(_sqlDataAdapter);
_sqlCommandBuilder.ConflictOption = ConflictOption.OverwriteChanges;
_sqlCommandBuilder.SetAllValues = false;
_sqlDataAdapter.Update(DataTable);
I also get the schema:
_sqlDataAdapter.Fill(DataTable);
_sqlDataAdapter.FillSchema(_dataTable, SchemaType.Mapped);
Why is ADO.NET setting NULL for my column X although I did NOT set it?
I thought that when I do not set the value of the column X, ADO.NET gets the default value from the given constraint.
Is the ADO.NET CommandBuilder able to use default constraints?
回答1:
You do not need to use a CommandBuilder
to implement the update method for your DataAdapter
. The CommandBuilder
is full of issues. You can set the DataAdapter.SelectCommand
and the DataAdapter.UpdateCommand
properties to DbCommand
objects that specify the sql directly. This avoids the problems inherent in the CommandBuilder
's ability to generate proper sql statements.
Update:
There is no way for the CommandBuilder to know that you want to use the default value. All it does is generate an insert statement, if there is a column it is going to generate it for the insert statement. If that column is part of the insert statement, then any value given for that column, even null, will be inserted. The default value is for situations where you do not include it in the insert statement. It does not convert null into the default value, no matter how you try to insert the items, CommandBuilder or not.
Continuing down this path of trying to use the CommandBuilder is only going to give you more grief. It can't even handle a simple join statement in its select clause. It also requires a primary key. If either of these are violated then it cannot generate correct update, insert, and delete statements. Only two providers, Sql Server and Oracle, have ever implemented this class, and the Oracle one is known to have bugs that were never fixed outside of the basic problems mentioned above.
If you used two DbCommand objects, one for selecting and one for inserting, and then looped through the output of the select DbCommand via a DbDataReader, you could easily check for null in that column and provide the default value of zero to the insert DbCommand, since you know what it is. Knowing the rules of the database and using them when necessary is not a violation of any kind of code organization rules. You have to know what is in the database anyways in order to write this kind of code.
If you have sql server 2005 or up, another suggestion is to use the INSERT INTO .. SELECT statement. If your sql is good enough you can use a CASE clause to make a single sql statement.
回答2:
A little question, it may seem obvious, but in fact it's tricky.
_sqlCommandBuilder.ConflictOption = ConflictOption.OverwriteChanges;
If I quote MSDN definition you may read :
"If no PrimaryKey is defined, all searchable columns are included in the WHERE clause."
A friend of mine, used to define IDENTITY(1, 1) in some camses instead of Primary keys.
So little question is, do you use primary key in your "updated" table B ??
then....
To add informations, SqlAdapter.FillSchema does not use default values Here are informations retrieved by FillSchema :
AllowDBNull
AutoIncrement.You must set AutoIncrementStep and AutoIncrementSeed separately.
MaxLength
ReadOnly
Unique
(Quote from MSDN site)
Unique
来源:https://stackoverflow.com/questions/5868313/ado-net-commandbuilder-insertcommand-and-default-constraints