none
DataColumn.DefaultValue nicht gefüllt RRS feed

  • Frage

  • Hallo Community,

    ich habe den Eindruck, dass die DefaultValue-Eigenschaft eines DataColumn-Objektes nie gefüllt wird.
    Sie ist stets identisch mit System.DBNaull.Value.
    Was läuft schief?

     

    Hier mein Testszenario:

    Anlegen einer Tabelle im SQL-Server:
    =====Script-Anfang=========================
    USE [myCatalog] /**ANPASSEN**/
    GO

    /****** Object:  Table [dbo].[yUserTest]    Script Date: 10/18/2011 17:26:56 ******/
    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    CREATE TABLE [dbo].[yUserTest](
     [usrUser] [nvarchar](64) NOT NULL,
     [usrName] [nvarchar](64) NOT NULL,
     [usrYnActive] [bit] NOT NULL,
     CONSTRAINT [PK_yUserTest_1] PRIMARY KEY CLUSTERED
    (
     [usrUser] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

    ALTER TABLE [dbo].[yUserTest] ADD  CONSTRAINT [DF_yUserTest_usrName]  DEFAULT (N'(N''MisterX'')') FOR [usrName]
    GO

    ALTER TABLE [dbo].[yUserTest] ADD  CONSTRAINT [DF_yUserTest_usrYnActive]  DEFAULT ((1)) FOR [usrYnActive]
    GO

    =====Script-Ende===========================

    =====C#-Testprogramm======Start
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    using System.Data.OleDb;
    using System.Data;

    namespace prj4Tests
    {
        class TestDefaultValue
        {

            static void Main(String[] args)
            {
                String myDataSource = @"XXXXXX"; /**Anpassen**/
                String myCatalog = @"XXXXX"; /**Anpassen**/

                String strCnn = @"Provider=SQLOLEDB.1;Data Source=" + myDataSource
                    + ";Integrated Security=SSPI;Initial Catalog=" + myCatalog;

                OleDbConnection cnn = null;
                cnn = new OleDbConnection(strCnn);

                if (!(cnn == null))
                {
                    cnn.Open();
                    String strSelect = "SELECT * FROM yUserTest";
                    DataTable dt = new DataTable();

                    using (OleDbCommand cmd = new OleDbCommand(strSelect, cnn))
                    {
                        using (OleDbDataAdapter da = new OleDbDataAdapter(cmd))
                        {
                            da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
                            da.Fill(dt);

                            da.FillSchema(dt, SchemaType.Mapped);
                            foreach (DataColumn dc in dt.Columns)
                            {
                                Debug.WriteLine("DataColumn.DefaultValue = <" + dc.DefaultValue + ">");
                            }
                        }
                    }  
                }
            }
        }
    }

    =====C#-Testprogramm======Ende


    ======Ausgabe==========
    DataColumn.DefaultValue = <>
    DataColumn.DefaultValue = <>
    DataColumn.DefaultValue = <>
    ======Ausgabe==========

    Dienstag, 18. Oktober 2011 15:47

Antworten

  • Hallo,

    das liegt daran, dass eine Default Einschränkung nur in einfachsten Fällen (Konstante) passt.
    Zulässig und üblich sind dort aber auch Funktionen, z. B. GETDATE() bei Datumsspalten oder NEWID bei uniqueidentifier,
    Funktionen können durch einen DataColumn.DefaultValue nicht abgebildet werden und direkt interpretiert
    würden sie falsche Ergebnisse liefern.

    Deswegen werden sie bei GetSchemaTable (SqlClient, OleDb oder Odbc) nicht zurückgeliefert.
    Verwendet (und ausgewertet) werden sie nur, wenn Du beim INSERT DEFAULT für eine Spalte angibst
    bzw. DEFAULT VALUES verwendest.

    Soweit es sich um Konstanten handelt, kannst Du sie z. B. über die INFORMATION_SCHEMA.COLUMNS abrufen.

    Gruß Elmar

    Mittwoch, 19. Oktober 2011 08:53
    Beantworter
  • Hi,
  • Mein Beispiel war bewusst so gewählt, dass lediglich Konstanten als DefaultValues gewählt wurden.
  • In der Beschreibung zu DataColumn.DefaultValue wird ausdrücklich erwähnt, dass Werte zurückgegeben werden. http://msdn.microsoft.com/en-us/library/system.data.datacolumn.defaultvalue.aspx 
  • da steht aber nichts davon, dass diese Werte automatisch über den Datenbanktreiber zugewiesen werden, sondern dass man den Wert manuell setzen und _dann_ auch wieder auslesen kann.
  • Information_Schema.Columns liefert auch bei komplexen Default-Werten (die z.B. indirekt über einen benutzterdefinierten Datentyp festgelegt wurden) entsprechende Werte zurück.
  • Das ist schon richtig. Aber Du verwechselst DBMS interne Mechanismen mit einer "generischen" DataTable, die für alle Datenmengen verwendet werden kann, unabhängig von Ihrer Herkunft. Zudem werden die Werte von der DataTable erzeugt. Wenn Du bspw. GETDATE() in SQL Server als Standardwert zuweist, wird das erst beim effektiven INSERT ermittelt. Wenn Du das vorab in einer DataTable machst, wird das zur Laufzeit, also beim Erzeugen des Datensatzes in der DataTable gemacht. Hier kann es dann schon Unterschiede geben, je nach genauer Umsetzung im Sekunden, aber auch im Stundenbereich.

    IIRC wird DefaultValue nur für die DataTable selbst verwendet. Und dazu muss man die Werte auch selbst setzen. Einzig bei einem stark typisierten DataSet könnte es anders sein, damit hab ich aber ehrlich gesagt noch nie was gemacht.

    Du kannst dir natürlich eine eigene DataTable Klasse schreiben, die dann beim Füllen über den DataAdapter auch gleich wieder die SQL Server internen Standardwerte ausliest und diese dann der DefaultValue Eigenschaft zuweist.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 19. Oktober 2011 12:12
    Moderator
  • Hallo,

    ergänzend zu den Erläuterungen von Stefan:

    DataColumn.DefaultValue darfst Du gerne mit eigenen Werte belegen -
    tue ich auch, allerdings mache ich das via Code und nur für echte Konstanten.

    DefaultValue kann nur mit Konstanten umgehen - deswegen eignet sie sich auch nur dafür,
    also z. B. für die "1" oben.

    CURRENT_TIMESTAMP wäre aber eine Funktion (als Alias für GetDate),
    die beim Einfügevorgang mit der Zeit des Servers besetzt wird.
    Den Wert lokal zu befüllen würde insofern eine Zeitdifferenz bedeuten,
    Klein aber fein, selbst dann wenn die Uhren synchron gehalten werden.

    Legt man ihn bereits bei der Erzeugung der DataTable fest, so wird der
    Wert mit fortschreitender Laufzeit immer mehr daneben liegen.
    Da wäre eine DataTable Ereignis wie TableNewRow besser geeignet.

    Ich verwende da aber lieber das passende INSERT (via DEFAULT oder weglassen)
    und lese den Wert in die DataTable zurück.

    Mehr habe ich dazu vor Jahren was erzählt, wie man die Werte abrufen könnte:
    Funktion zum setzen der DefaultValues

    Gruß Elmar

    Mittwoch, 19. Oktober 2011 13:08
    Beantworter

Alle Antworten

  • Hallo,

    das liegt daran, dass eine Default Einschränkung nur in einfachsten Fällen (Konstante) passt.
    Zulässig und üblich sind dort aber auch Funktionen, z. B. GETDATE() bei Datumsspalten oder NEWID bei uniqueidentifier,
    Funktionen können durch einen DataColumn.DefaultValue nicht abgebildet werden und direkt interpretiert
    würden sie falsche Ergebnisse liefern.

    Deswegen werden sie bei GetSchemaTable (SqlClient, OleDb oder Odbc) nicht zurückgeliefert.
    Verwendet (und ausgewertet) werden sie nur, wenn Du beim INSERT DEFAULT für eine Spalte angibst
    bzw. DEFAULT VALUES verwendest.

    Soweit es sich um Konstanten handelt, kannst Du sie z. B. über die INFORMATION_SCHEMA.COLUMNS abrufen.

    Gruß Elmar

    Mittwoch, 19. Oktober 2011 08:53
    Beantworter
  • Hallo  Elmar.

    zunächst einmal vielen Dank für die Antwort.

    Leider ist sie nicht sehr befriedigend für mich.

    • Mein Beispiel war bewusst so gewählt, dass lediglich Konstanten als DefaultValues gewählt wurden.
    • In der Beschreibung zu DataColumn.DefaultValue wird ausdrücklich erwähnt, dass Werte zurückgegeben werden. http://msdn.microsoft.com/en-us/library/system.data.datacolumn.defaultvalue.aspx 
    • Die Tatsache, dass es u.U. schwierig ist, den DefaultValue korrekt zu interpretieren, ist zunächst einmal zweitrangig
    • Information_Schema.Columns liefert auch bei komplexen Default-Werten (die z.B. indirekt über einen benutzterdefinierten Datentyp festgelegt wurden) entsprechende Werte zurück.
      Beispiele:
      >create default [Now] as CURRENT_TIMESTAMP   
      >create default [initDecimalEins] as 1   
      >  /****** Object:  Default [dbo].[initInt]    Script Date: 07/16/2011 17:52:45 ******/  create default [dbo].[initTriState] as -1     

    Können wir uns auf folgende Aussage einigen?

    "DataColumn.DefaultValue liefert immer SYSTEM.DBNull.Value zurück"

     

    Mittwoch, 19. Oktober 2011 11:34
  • Hi,
  • Mein Beispiel war bewusst so gewählt, dass lediglich Konstanten als DefaultValues gewählt wurden.
  • In der Beschreibung zu DataColumn.DefaultValue wird ausdrücklich erwähnt, dass Werte zurückgegeben werden. http://msdn.microsoft.com/en-us/library/system.data.datacolumn.defaultvalue.aspx 
  • da steht aber nichts davon, dass diese Werte automatisch über den Datenbanktreiber zugewiesen werden, sondern dass man den Wert manuell setzen und _dann_ auch wieder auslesen kann.
  • Information_Schema.Columns liefert auch bei komplexen Default-Werten (die z.B. indirekt über einen benutzterdefinierten Datentyp festgelegt wurden) entsprechende Werte zurück.
  • Das ist schon richtig. Aber Du verwechselst DBMS interne Mechanismen mit einer "generischen" DataTable, die für alle Datenmengen verwendet werden kann, unabhängig von Ihrer Herkunft. Zudem werden die Werte von der DataTable erzeugt. Wenn Du bspw. GETDATE() in SQL Server als Standardwert zuweist, wird das erst beim effektiven INSERT ermittelt. Wenn Du das vorab in einer DataTable machst, wird das zur Laufzeit, also beim Erzeugen des Datensatzes in der DataTable gemacht. Hier kann es dann schon Unterschiede geben, je nach genauer Umsetzung im Sekunden, aber auch im Stundenbereich.

    IIRC wird DefaultValue nur für die DataTable selbst verwendet. Und dazu muss man die Werte auch selbst setzen. Einzig bei einem stark typisierten DataSet könnte es anders sein, damit hab ich aber ehrlich gesagt noch nie was gemacht.

    Du kannst dir natürlich eine eigene DataTable Klasse schreiben, die dann beim Füllen über den DataAdapter auch gleich wieder die SQL Server internen Standardwerte ausliest und diese dann der DefaultValue Eigenschaft zuweist.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 19. Oktober 2011 12:12
    Moderator
  • Hallo,

    ergänzend zu den Erläuterungen von Stefan:

    DataColumn.DefaultValue darfst Du gerne mit eigenen Werte belegen -
    tue ich auch, allerdings mache ich das via Code und nur für echte Konstanten.

    DefaultValue kann nur mit Konstanten umgehen - deswegen eignet sie sich auch nur dafür,
    also z. B. für die "1" oben.

    CURRENT_TIMESTAMP wäre aber eine Funktion (als Alias für GetDate),
    die beim Einfügevorgang mit der Zeit des Servers besetzt wird.
    Den Wert lokal zu befüllen würde insofern eine Zeitdifferenz bedeuten,
    Klein aber fein, selbst dann wenn die Uhren synchron gehalten werden.

    Legt man ihn bereits bei der Erzeugung der DataTable fest, so wird der
    Wert mit fortschreitender Laufzeit immer mehr daneben liegen.
    Da wäre eine DataTable Ereignis wie TableNewRow besser geeignet.

    Ich verwende da aber lieber das passende INSERT (via DEFAULT oder weglassen)
    und lese den Wert in die DataTable zurück.

    Mehr habe ich dazu vor Jahren was erzählt, wie man die Werte abrufen könnte:
    Funktion zum setzen der DefaultValues

    Gruß Elmar

    Mittwoch, 19. Oktober 2011 13:08
    Beantworter
  • Hallo JottEss,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert

    Montag, 28. November 2011 07:34
    Moderator