none
c# mdb Tabelle programmgesteuert Erstellen / Fehler

    Frage

  • Hallo,

    ich muss programmgesteuert eine ACCESS Datenbank erstellen. Zur Erstellung nutze ich ADOX. Der leere Catalog wird sauber erstellt. Ein im Netz viel verbreitetes Beispiel.

    Beim Erstellen einer Tabelle gibt es allerdings folgendes Problem (Name, Colums sind ohne Fehler definiert):

    cat.Tables.Append( tbl);

    Erzeugt: "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."

    Obwohl vorher:

    ADOX.Catalog cat = new ADOX.Catalog();

    ADOX.Table tbl = new ADOX.Table();

    Bis zum genannten Fehler laufen alle Zugriffe auf cat und tbl (z.B.  tbl.Name = "Test";) fehlerfrei.

    Zur Info:

    using ADOX;

    using ADODB;

    using System.Data.OleDb;

    Montag, 28. Oktober 2013 09:35

Antworten

  • Hallo Holger,

    hier mal ein Beispiel für MDB mit ADODB / ADOX 2.8 (dafür ist der Jet 4.0 Provider ausgelegt):

    using System.Data.OleDb;
    
    namespace ElmarBoye.Samples.Data
    {
        public class ADOXCreateTable
        {
            const string ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\TEMP\Test.mdb;";
    
            public static void AddImageTable()
            {
                System.IO.File.Delete(@"C:\TEMP\Test.mdb"); // Create new
    
                ADOX.Catalog catalog = new ADOX.Catalog();
                catalog.Create(ConnectionString);
    
                ADOX.Table imageTable = new ADOX.Table();
                imageTable.Name = "Images";
                // Required to access provider properties
                imageTable.ParentCatalog = catalog;
                imageTable.Columns.Append("ImagesID", ADOX.DataTypeEnum.adInteger);
    
                imageTable.Columns.Append("CatalogueIndex", ADOX.DataTypeEnum.adInteger);
                imageTable.Columns.Append("ModelIndex", ADOX.DataTypeEnum.adInteger);
                imageTable.Columns.Append("ModelImage", ADOX.DataTypeEnum.adLongVarBinary);
    
                imageTable.Columns["ImagesID"].Properties["AutoIncrement"].Value = true;
    
                ADOX.Index imageTablePrimaryKey = new ADOX.Index();
                imageTablePrimaryKey.Name = "PK_Images";
                imageTablePrimaryKey.PrimaryKey = true;
                imageTablePrimaryKey.Columns.Append("ImagesID");
                imageTable.Indexes.Append(imageTablePrimaryKey);
    
                catalog.Tables.Append(imageTable);
    
                ADODB.Connection connection = (ADODB.Connection)catalog.ActiveConnection;
                connection.Close();
            }
    
            public static void AddImageTableSQL()
            {
                using (OleDbConnection connection = new OleDbConnection(ConnectionString))
                {
                    connection.Open();
    
                    OleDbCommand command = new OleDbCommand(
                        "CREATE TABLE Images2 (" +
                        "    ImageID Integer NOT NULL IDENTITY(1, 1), " +
                        "    CatalogueIndex Integer NOT NULL, " +
                        "    ModelIndex Integer NOT NULL, " +
                        "    ModelImage LONGBINARY NULL, " +
                        "    CONSTRAINT PK_Images2 PRIMARY KEY (ImageID));",
                        connection);
                    command.ExecuteNonQuery();
    
                    // Additional Index
                    command.CommandText = "CREATE INDEX Images2_CatalogueIndex ON Images2 (CatalogueIndex);";
                    command.ExecuteNonQuery();
                }
            }
        }
    }
    

    (Das Visual Basic Gegenstück findet sich hier ;)

    Dazu eine äquivalente Methode, die auf ADOX verzichtet und anstatt dessen SQL verwendet.

    Denn bis auf das Anlegen einer Datenbank kann man so ziemlich alles mit JET SQL erleddigen, und vermeidet den länglichen und fehleranfälligen ADOX-Code, siehe  Fundamental Microsoft Jet SQL for Access 2000

    Gruß Elmar

    Montag, 28. Oktober 2013 11:29
    Beantworter

Alle Antworten

  • Hallo,
    der Fehler "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt." kommt normalerweise daher, das irgend etwas nicht richtig zugewiesen wurde.
    Ich habe mal Testweise eine Datenbank erstellt:

                ADOX.Catalog cat = new ADOX.Catalog();
                cat.Create(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\test\MyDb2.mdb;Jet OLEDB:Engine Type=5");
                ADOX.Table tbl = new ADOX.Table();
                tbl.Name = "tBeispielTabelle";
                cat.Tables.Append(tbl);

    Es verlief alles Problemlos.

    Wenn der Debugger anhält, dann Zeige mal mit der Maus auf die eizelnen Variablen, dadurch werden dir die Werte angezeigt.

    Welche ADOX-Version hast du denn referenziert? (2.7, 2.8, 6.0, ...). Ich verwendete 6.0.
    Was kommt denn für eine Eception und gibt es eine innere Exception?


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Montag, 28. Oktober 2013 09:56
  • Hallo Tom,

    zuerst vielen Dank für die schnelle Antwort.

    ADOX ist 2.8

    Zur Info: Ich habe bis 2007 VBA unter ACCESS programmiert und steige jetzt wieder neu ein. Die Entscheidung zwischen VB und C# habe ich zu Gunsten C# entschieden. War das gut? (bin lernfähig).

    OK, habe

    cat= null; (im WEB-Beispiel)

    entfernt. War klar -Tage getestet- sorry.

    Jetzt habe ich den alten Fehler:

    Wert: cat {System.__ComObject}

    cat.Tables.Append(tbl); -> Die Typangabe ist ungültig.

    Das kann nicht viel sein, aber der Affe und die Kokosnuss....

    Grüße

    Holger


    • Bearbeitet ferrixLO Montag, 28. Oktober 2013 17:40
    Montag, 28. Oktober 2013 10:52
  • Hallo Holger,

    könntest Du ein minimales aber lauffähiges Beispiel (bis auf den bei dir zu sehenden Fehler natürlich) bereitstellen? Einfach den Code soweit komprimieren, dass eine Tabelle mit einer oder zwei Spalte(n) erzeugt wird und der Fehler reproduzierbar ist.

    Zur Frage: VB oder C#. Beides ist Ok, es kommt da eher auf die persönlichen Vorlieben bzgl. der Syntax an. Von den Möglichkeiten her geben sich die beiden Sprachen nichts, letztendlich kommt eh immer dasselbe raus. (Ja, es gibt kleinere Unterschiede, die wirken sich in der Praxis aber in der Regel nicht wirklich aus)


    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

    Montag, 28. Oktober 2013 11:11
  • Hallo Tom,

    habe die Beispiele aus allen Foren verworfen und Dein Beispiel verwendet:

    -it runs!-

    Jetzt kommen die Felder. Ich hoffe du begleitest mich noch ein Stück.

    Holger

    Montag, 28. Oktober 2013 11:23
  • Hallo Holger,

    hier mal ein Beispiel für MDB mit ADODB / ADOX 2.8 (dafür ist der Jet 4.0 Provider ausgelegt):

    using System.Data.OleDb;
    
    namespace ElmarBoye.Samples.Data
    {
        public class ADOXCreateTable
        {
            const string ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\TEMP\Test.mdb;";
    
            public static void AddImageTable()
            {
                System.IO.File.Delete(@"C:\TEMP\Test.mdb"); // Create new
    
                ADOX.Catalog catalog = new ADOX.Catalog();
                catalog.Create(ConnectionString);
    
                ADOX.Table imageTable = new ADOX.Table();
                imageTable.Name = "Images";
                // Required to access provider properties
                imageTable.ParentCatalog = catalog;
                imageTable.Columns.Append("ImagesID", ADOX.DataTypeEnum.adInteger);
    
                imageTable.Columns.Append("CatalogueIndex", ADOX.DataTypeEnum.adInteger);
                imageTable.Columns.Append("ModelIndex", ADOX.DataTypeEnum.adInteger);
                imageTable.Columns.Append("ModelImage", ADOX.DataTypeEnum.adLongVarBinary);
    
                imageTable.Columns["ImagesID"].Properties["AutoIncrement"].Value = true;
    
                ADOX.Index imageTablePrimaryKey = new ADOX.Index();
                imageTablePrimaryKey.Name = "PK_Images";
                imageTablePrimaryKey.PrimaryKey = true;
                imageTablePrimaryKey.Columns.Append("ImagesID");
                imageTable.Indexes.Append(imageTablePrimaryKey);
    
                catalog.Tables.Append(imageTable);
    
                ADODB.Connection connection = (ADODB.Connection)catalog.ActiveConnection;
                connection.Close();
            }
    
            public static void AddImageTableSQL()
            {
                using (OleDbConnection connection = new OleDbConnection(ConnectionString))
                {
                    connection.Open();
    
                    OleDbCommand command = new OleDbCommand(
                        "CREATE TABLE Images2 (" +
                        "    ImageID Integer NOT NULL IDENTITY(1, 1), " +
                        "    CatalogueIndex Integer NOT NULL, " +
                        "    ModelIndex Integer NOT NULL, " +
                        "    ModelImage LONGBINARY NULL, " +
                        "    CONSTRAINT PK_Images2 PRIMARY KEY (ImageID));",
                        connection);
                    command.ExecuteNonQuery();
    
                    // Additional Index
                    command.CommandText = "CREATE INDEX Images2_CatalogueIndex ON Images2 (CatalogueIndex);";
                    command.ExecuteNonQuery();
                }
            }
        }
    }
    

    (Das Visual Basic Gegenstück findet sich hier ;)

    Dazu eine äquivalente Methode, die auf ADOX verzichtet und anstatt dessen SQL verwendet.

    Denn bis auf das Anlegen einer Datenbank kann man so ziemlich alles mit JET SQL erleddigen, und vermeidet den länglichen und fehleranfälligen ADOX-Code, siehe  Fundamental Microsoft Jet SQL for Access 2000

    Gruß Elmar

    Montag, 28. Oktober 2013 11:29
    Beantworter
  • Hallo Leute,

    vielen Dank für die rege Betieligung und Hilfsbereitschaft.

    an Stefan: Siehe oben, Tom. DasBeispiel läuft.

    Ich werde mich jetzt mal an das Beispiel von Elmar machen.

    Holger

    Montag, 28. Oktober 2013 11:48
  • Hallo Elmar,

    ein gut gemeintes Stück Code.

    Wenn es jetzt noch als Konsolenanwendung läuft, hilfst Du Vielen im Netz.

    (Einbindung in main{})

    Ein einfaches, lauffähiges Beispiel für eine Konsolenanwendung würde  Dir sicher viel Dank und Ehre bringen ;-)

    Ich suche seit Tagen danach, ohne Erfolg.

    Viele Grüße

    Holger

    Montag, 28. Oktober 2013 17:34
  • Hallo Tom,

    vielen Dank für den sauberen Code.

    Wenn ich bitten darf, ist auch noch das Erstellen von Tabellenfeldern / -spalten wichtig. Hast Du da auch so eine schnelle Lösung?

    Holger

    Montag, 28. Oktober 2013 17:39
  • Hallo Holger,

    es sollte doch für dich machbar sein, Elmars Beispiel in einer main Methode einer Konsolenanwendung aufzurufen. Dann gebührt der Dank auch dir :) Also ran ans Werk.

    Allerdings finde ich, auch nach dem weiteren Posting in Richtung Tom, deine Erwartungshaltung nicht passend. Probier doch erst einmal selbst, die weiteren Schritte einzubauen. Wenn Du dann ein konkretes Problem hast, helfen wir hier sicher alle gerne weiter.


    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

    Montag, 28. Oktober 2013 17:54
  • Hallo Stefan,

    danke für die Mitarbeit.

    Leider habe ich noch keine brauchbare Datenbank. Das Erzeugen läuft fehlerfrei, dann ist Schluss. Für ACCESS habe ich leider nur noch die Runtime. Testen muss ich also in meiner Applikation.

    Das Beispiel von Tom läuft fehlerfrei durch.

    Mein Ziel ist, eine Konsolenanwendung zu basteln, die eine .mdb mit einer Tabelle und 3 Felden erzeugt.

    - klingt komisch, gibt es aber im gesamten Netz nicht -

    Für Profis ist das sicher zu simpel. Einsteigern verwehrt es aber den Zugang. Freue mich über jede Hilfe!

    Viele Grüße

    Holger

    Montag, 28. Oktober 2013 17:55
  • Hallo Stefan,

    Dank für das Vertrauen. Aber ich bin einfach am Ende - 5 Tage Google- . Heute noch ein Erfolgserlebnis, oder ich schmeisse den Mist hin.

    Das Einbinden in Main{} ist sicher kein Prob. Ich muss aber eine Datenbank entwickeln, nicht C# dressieren.

    Euch sei die Ehre. Hauptsache ich kann arbeiten.

    Holger

    Montag, 28. Oktober 2013 18:18
  • Hallo Holger,

    Dank für das Vertrauen. Aber ich bin einfach am Ende - 5 Tage Google- . Heute noch ein Erfolgserlebnis, oder ich schmeisse den Mist hin.

    evtl. verstehst Du den Sinn und Zweck des Forums ein wenig falsch. Das Forum dient nicht dazu, dir größeren lauffähigen Code vorzuschmeißen, sondern eher als Hilfe zur Selbsthilfe. D.h. Du hast ein konkretes Problem, mit dem Du dich sinnvollerweise auch schon beschäftigt hast, in einem Entwicklerforum auch mit entsprechendem Code, den Du hier zeigen solltest. Wenn es dann an 1, 2, 3, ganz vielen Stellen hakt, kann man diese Probleme gemeinsam durchgehen und dir Lösungsmöglichkeiten aufzeigen.

    Das Einbinden in Main{} ist sicher kein Prob. Ich muss aber eine Datenbank entwickeln, nicht C# dressieren.

    Das, was Du da grade machst, hat mit Datenbankentwicklung ungefähr soviel zu tun wie .NET mit einer Haustür. Man könnte zwar eine Haustürsteuerung auf .NET Basis bauen, die Haustür an sich hat aber mit .NET rein gar nichts zu tun. Das, was Du da machst ist .NET Programmierung. Dass dabei dann zufällig etwas rauskommt, was nach einer Datenbank aussieht, mag zwar so sein, letztendlich ist das aber Programmierung und keine Datenbankentwicklung.

    Euch sei die Ehre. Hauptsache ich kann arbeiten.

    In diesem Fall würde ich dir empfehlen, dir einen Dienstleister mit ins Boot zu holen, der die ehrenhaften Aufgaben gegen Bezahlung übernimmt.

    Elmars Code macht das, was Du willst. Wenn Du wirklich nicht in der Lage sein solltest, das in eine Konsolenanwendung zu packen und Du nicht willens bist, es überhaupt mal zu versuchen, solltest Du überlegen, ob es wirklich sinnvoll ist, sich weiterhin mit Programmierung zu beschäftigen. Ich mein, jeder hat mal angefangen und stand dann vor Problemen. Sich dann aber trotz sehr guter Beispiele nicht weiter damit beschäftigen zu wollen, führt in den allerwenigsten Fällen zu etwas brauchbarem.

    Nur soviel: Um die von Elmar gezeigte(n) Methode(n) aufzurufen, musst Du an der gewünschten Stelle nichts weiter machen als:

    ElmarBoye.Samples.Data.ADOXCreateTable.AddImageTable();

    bzw.

    ElmarBoye.Samples.Data.ADOXCreateTable.AddImageTableSQL();
    aufzurufen.


    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


    Montag, 28. Oktober 2013 18:36
  • Alles was nicht in main läuft, das läuft nirgends. (Manches macht sicher keinen Sinn)

    Nach ein wenig Sucharbeit fand ich die Referenz für ADOX in der MSDN:
    http://msdn.microsoft.com/de-de/library/office/jj249446.aspx

    Beispiele gibts auch noch:
    http://msdn.microsoft.com/de-de/library/office/jj249443.aspx
    Aber leider nicht in C#. Bis auf die Syntax ist es aber gleich zu C#.

    Ansonsten kann ich Stefan nur zustimmen.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Montag, 28. Oktober 2013 18:46
  • Hallo Stefan, Elmar und Co.,

    da habe ich ein schlechtes Beispiel gegeben, wie man es nicht angehen sollte - sorry-.

    Eventuell kann das aber auch für Andere lehrreich sein: Wenn man mal überarbeitet ist, Ma.. halten, abschalten, Frischluft schnuppern....  Den Rüffel von Stefan habe ich verstanden und auch verdient.

    Ich hatte nie vor, das Forum als "Programmiermaschine" zu nutzen. Das sollte Jeder logischer Weise selbst machen, oder anfangen zu Häkeln. Entschuldigung wenn es so herüberkam.

    Zum Thema Datenbank möchte ich mich ein wenig richtigstellen. Ich bin zwar kein Gründervater wie Edgar F. Codd, arbeite aber mit RDBMS seit ca. 1985. Derzeit arbeite ich an einer DB welche ich gern im Frontend mit C# programmieren möchte. Am ACCESS-Format sind Macken im Projektumfeld schuld. Leider fehlt mir in C# noch das berühmte "Hallo Welt" bei der .mdb Erstellung.

    Das Letzte war der berühmte "Monitor aus dem Fenster-Wurf". Es gehört nicht in Dieses Forum, kann aber eventuell anderen Nutzern als Mahnung dienen. - So geht es nicht -   In fast 30 Jahren Programmierung habe ich so viele Bretter und Beulen am Kopf, dass ich mich kaum selbst noch erkenne.

    Ich würde das Projekt gern weiter betreiben und mich damit beschäftigen. Den Rüffel habe ich wohl gebraucht. Nach Abschluss des Projektes sollten wir wohl den nicht-sachlichen Teil entfernen?

    Grüße

    Holger

    Dienstag, 29. Oktober 2013 11:05
  • Hi,

    Leider fehlt mir in C# noch das berühmte "Hallo Welt" bei der .mdb Erstellung.

    für mich stellt sich die Frage, warum Du die DB überhaupt per Code erstellen willst?

    In solchen Fällen hab ich es bisher so gehandhabt, dass ich die .mdb Datei (quasi als Vorlage) als Ressource in der Anwendung mitgeführt habe. Die .mdb war dabei schon mit allen Tabellen, Sichten, ... bestückt. War die Datenbankdatei auf dem Zielsystem noch nicht vorhanden, habe ich diese aus den Resourcen extrahiert und auf dem Zielsystem in den passenden Ordner geschrieben. Damit hat man dann schon alles, was man braucht. Ein Beispiel hierfür findest Du hier:

      http://stackoverflow.com/questions/864140/write-file-from-assembly-resource-stream-to-disk

    Die .mdb inkl. aller dahin enthaltenen Objekte zur Laufzeit zu erstellen, macht IMO eigentlich nur dann Sinn, wenn der Aufbau sehr dynamisch und/oder von Benutzereingaben beim ersten Programmstart abhängig ist.


    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

    Dienstag, 29. Oktober 2013 19:27
  • Hallo Stefan,

    leider mangels Masse kann ich in ACCESS nichts mehr vorbereiten. Deine Lösung ist ganz einfach, das habe ich auch betrieben. In der geplanten Umgebung habe ich leider keinen (finanzierbaren) Zugriff auf ACCESS mehr. Traurig, aber wahr.

    (Zu viel Sicherheit führt zu gelben Zetteln am Monitor)

    Ich muss eine Applikation bauen, die eine eigene DB erzeugt, die sich auch bei Updates selbst modifizieren kann. Darum dieser Ansatz. So wie Du habe ich früher auch gearbeitet, leider geht das hier nicht.

    Ich muss sehr dynamisch arbeiten, auch bei der Erstinstallation.

    Dank Euerer Hilfe bin ich so ganz langsam wieder in der Spur.

    Viele Grüße

    Holger

    Mittwoch, 30. Oktober 2013 18:02
  • Hallo Holger,

    in dem Fall würde ich dann eine leere MDB Datei in die Ressourcen einbinden (die wird es ja geben, oder?) und die einzelnen SQL Statements als Stringresourcen mitführen. Bei der Installation bzw. beim Erstaufruf deiner Anwendung kopierst Du dann die MDB aus den Ressourcen ins Dateisystem, öffnest ganz normale deine OleDbConnection und setzt die einzelnen SQL Statements per:

    <OleDbCommand>.CommandText = "CREATE TABLE ...";
    <OleDbCommand>.ExecuteNonQuery();

    gegen die Datenbank ab. Hier findest Du weitere Infos zu ExecuteNonQuery.

      http://msdn.microsoft.com/DE-DE/library/system.data.oledb.oledbcommand.executenonquery.aspx

    Eine Stringressource kannst in den Projekteigenschaften anlegen und dann per

    String CommandText1 = Properties.Resource.<NameDeinerResource>;

    auslesen. Wenn das ein gültiges SQL Statement (auch CREATE TABLE ... oder ähnliches geht da) kannst Du das mit dem oben gezeigten <OleDbCommand>.ExcecuteNonQuery ausführen lassen.


    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, 30. Oktober 2013 18:52
  • Hallo Ciprian,

    das Beispiel von Elmar ist die Lösung. Ich würde nur gern mit Stefan zusammen den privaten, unsachlichen Teil entfernen.

    Dann schreibe ich noch einen kleinen Dank und schließe den Thread.

    An C# habe ich mich festgebissen und werde dabei bleiben.

    Holger

    Freitag, 1. November 2013 09:23