Announcement

Collapse
No announcement yet.

Problem beim Verbinden von Tabellen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem beim Verbinden von Tabellen

    Hallo,
    ich muss zugeben das ich mich mit Datenbanken noch nicht so gut auskenne und auch nicht mit C#, da ich sonst in C++ programmiere, wobei sich da die ADOX-Programmierung aber viel komplizierter rausstellte.
    Ich benutze VC 2008.
    In dem folgenden Code will ich mit ADOX an sich einfach nur eine Datenbank mit zwei Tabellen anlegen: einmal fuer Buecher und einmal fuer Autoren. Die Buecher besitzen ein Feld AuthorID um auf einen Eintrag in der anderen Tabelle zu verweisen. Nichtbeteiligte Spalten habe ich der Uebersicht halber rausgenommen.
    Code:
    static  void Tabellen_anlegen(String Name)
            {
                ADOX.Column column;
    
                
                ADOX.Catalog catalog = new ADOX.Catalog();
                catalog.Create("Provider=Microsoft.Jet.OLEDB.4.0;" +
                       "Data Source=E:\\NewMDB.mdb;");
    
    //Spalte für ID
                ADOX.Table Buecher = new ADOX.Table();
                Buecher.Name = "Books";
                column = new ADOX.Column();
                column.ParentCatalog = catalog;
                column.Name = "ID";
                column.Type = ADOX.DataTypeEnum.adInteger;
                column.Properties["Nullable"].Value = false;
                column.Properties["AutoIncrement"].Value = true;
                Buecher.Columns.Append(column, ADOX.DataTypeEnum.adIUnknown, 0);
    
    //Spalte für einen Verweis auf den Autor
                column = new ADOX.Column();
                column.ParentCatalog = catalog;
                column.Name = "AuthorID";
                column.Type = ADOX.DataTypeEnum.adInteger;
                column.Properties["Nullable"].Value = false;
                Buecher.Columns.Append(column, ADOX.DataTypeEnum.adIUnknown, 0);
                Buecher.ParentCatalog = catalog;
    
    //Setzen des Primärindex auf ID
                ADOX.Index index = new ADOX.Index();
                index.Name = "PrimaryKey";
                index.PrimaryKey = true;
                index.Columns.Append("ID", Buecher.Columns["ID"].Type, Buecher.Columns["ID"].DefinedSize);
                Buecher.Indexes.Append(index, null);
                
    //Tabelle für die Autoren
                ADOX.Table Autoren = new ADOX.Table();
                Autoren.Name = "Authors";
    //ID für einen Autor
                column = new ADOX.Column();
                column.ParentCatalog = catalog;
                column.Name = "ID";
                column.Type = ADOX.DataTypeEnum.adInteger;
                column.Properties["Nullable"].Value = false;
                column.Properties["AutoIncrement"].Value = true;
                Autoren.Columns.Append(column, ADOX.DataTypeEnum.adIUnknown, 0);
                Autoren.ParentCatalog = catalog;
    //Setzen des Primärindex auf ID
                index = new ADOX.Index();
                index.Name = "PrimaryKey";
                index.PrimaryKey = true;
                index.Columns.Append("ID", Buecher.Columns["ID"].Type, Buecher.Columns["ID"].DefinedSize);
                Autoren.Indexes.Append(index, null);
                
    //Verknüpfen der Tabellen - AuthorID soll auf einen Autor in der anderen Tabelle zeigen           
                ADOX.Key key = new ADOX.Key();
                key.Name = "BuchAutor";
                key.Type = ADOX.KeyTypeEnum.adKeyForeign;
                key.RelatedTable = "Authors";
                key.Columns.Append("AuthorID", Buecher.Columns["AuthorID"].Type, Buecher.Columns["AuthorID"].DefinedSize);
                key.Columns["AuthorID"].RelatedColumn = "ID";
                key.DeleteRule = ADOX.RuleEnum.adRICascade;
                Buecher.Keys.Append(key, ADOX.KeyTypeEnum.adKeyForeign, null/*Type.Missing*/, null, null);
    
    //Hinzufügen der beiden Tabellen zur Datenbank
                catalog.Tables.Append(Autoren);
                catalog.Tables.Append(Buecher);
            }
    Der Compiler uebersetzt das ohne zu meckern, allerdings gibts dann beim Ausfuehren einen Laufzeitfehler:
    Unbehandelte Ausnahme: System.Runtime.InteropServices.COMException (0x800A0BB9):
    Ausnahme von HRESULT: 0x800A0BB9
    bei ADOX.Keys.Append(Object Item, KeyTypeEnum Type, Object Column, String Rel
    atedTable, String RelatedColumn)
    bei DatenbankTest_CS.Program.Tabellen_anlegen(String Name) in D:\Meine Visual
    Projekte\DatenbankTest_CS\DatenbankTest_CS\Program .cs:Zeile 117.
    bei DatenbankTest_CS.Program.Main(String[] args) in D:\Meine Visual Projekte\
    DatenbankTest_CS\DatenbankTest_CS\Program.cs:Zeile 126.
    Beim Debugggen habe ich herausgefunden, dass der Fehler in der Zeile "Buecher.Keys.Append(key, ADOX.KeyTypeEnum.adKeyForeign, null/*Type.Missing*/, null, null);" auftritt.
    An sich finde ich habe ich mich sehr gut an die Vorlage in einem Buch gehalten; kann mir diesen Fehler nicht erklaeren.
    Wisst ihr vielleicht wo der Fehler liegt, Hilfe waere echt nett!

    Vielen Dank schonmal im Vorraus,

    Andreas

  • #2
    Hallo,

    musst du ADOX verwendet oder kann ein .net-Bordmittel (ADO.net, Linq To SQL, Entity Framework) verwendet werden. Damit ist es wohl einfacher.


    mfG Gü
    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

    Comment


    • #3
      Muss es denn Access sein? Selbst von MS gibt es mit SQL Anywhere (oder wars SQL Everywhere) eine bessere Alternative.

      Comment


      • #4
        Hallo, erstmal vielen Dank für die Antworten!

        Es muss nicht ADOX sein, allerdings stand in dem Buch das ich gelesen habe, dass ADO.Net nicht so geeignet ist um auf Access-Datenbanken zuzugreifen.

        Ich fand Accessdatenbanken halt recht gut, weil da alles direkt in eine Datei gespeichert wird, die ich auch kopieren etc. kann. Zudem kann ich mir mit Access wirklich angucken was ich mit dem Programm bewirkt habe.
        Beim SQL-Server weiß ich nicht wo er das speichert - hab zwar eine Methode gesehen wie man eine Art Backup macht fand das aber umständlicher.

        Dachte an sich auch, dass ich oben nur einen typischen Anfängerfehler gemacht habe, oder kommt es bei ADOX häufiger zu unverständlichen Fehlermeldungen?

        Viele Grüße

        Andreas

        Comment


        • #5
          Wie oben geschrieben würd ich die Finger von Access lassen. Als Alternative zu dem oben gibts auch noch den SQL Server CE. Der läuft auch lokal und ich glaube man kann auch einfach nur die Datei mit den Daten kopieren.

          Comment


          • #6
            naja bin ja an sich für alles offen - nur was mich mal interessieren würde:

            Was spricht denn so gegen Access, außer das man nicht soviele Nutzer gleichzeitig haben kann ohne ordentlich Leistung zu verlieren (rechne eh mit max. 10 Nutzern)?
            Sowas wie Rechtverwaltung denke ich werde ich auch nicht groß benötigen - wo ist dann der Haken bei Access?

            Comment


            • #7
              Hallo,

              wo ist dann der Haken bei Access?
              ohne bestimmte Reihenfolge
              • ist keine Datenbank
              • wird oft korrupt
              • es gibt keine vernüftige Zugriffsprovider
              • es gibt keine Stored Procedures
              • es gibt keinen Query-Optimizier
              • ...lässt sich fast beliebig fortsetzen


              Das vorgeschlagenen SQL Compact ist sicherlich besser. Auch weil ein späterer Wechsel zum SQL Server (fast) ohne Aufwand geht.


              mfG Gü
              "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

              Comment


              • #8
                Ok überredet - werde mich dann damit mal auseinandersetzen. Dafür muss man dann ADO.Net verwenden, oder?

                Ist das denn in C++ auch so kompliziert zu handeln wie ADOX, sodass ich um C# nicht herumkomme, oder ist das auch in (managed) C++ einfach?
                (Ich weiß das ist ein C# forum - aber vielleicht hat ja jemand Erfahrung).

                Vielen Dank und viele Grüße

                Andreas

                Comment


                • #9
                  Hallo,

                  ADO.net arbeitet mit DataSet und SQL gegen/mit der Datenbank. Ich würde vorschlagen dass du einen O/R-Mapper verwendest denn somit kannst du mit Objekten arbeiten und die SQL-Erzeugung übernimmt der Mapper.

                  Somit entsteht natürlich die Qual der Wahl. Es gibt viele O/R-Mapper zur Auswahl. Der einfachste der beim .net-Framework dabei ist ist Linq To Sql. Für Tutorials siehe die LINQ to SQL Tutorials von Scott Guthrie.

                  Bevor die Frage zu Linq to Sql auftaucht: Es wird nicht mehr intensiv weiterentwickelt, bleibt aber Bestandteil des Framework.


                  mfG Gü
                  "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                  Comment


                  • #10
                    Ich denke, das Problem ist hier,dass die Refernz Beziehung Buecher/Autor angelegt werden soll noch bevor die Tabelle Autoren existiert.

                    Probier mal:

                    Code:
                    ....
                    
                    //Hinzufügen der Autoran zur Datenbank
                                catalog.Tables.Append(Autoren);
                    
                    
                    //Verknüpfen der Tabellen - AuthorID soll auf einen Autor in der anderen Tabelle zeigen           
                                ADOX.Key key = new ADOX.Key();
                                key.Name = "BuchAutor";
                                key.Type = ADOX.KeyTypeEnum.adKeyForeign;
                                key.RelatedTable = "Authors";
                                key.Columns.Append("AuthorID", Buecher.Columns["AuthorID"].Type, Buecher.Columns["AuthorID"].DefinedSize);
                                key.Columns["AuthorID"].RelatedColumn = "ID";
                                key.DeleteRule = ADOX.RuleEnum.adRICascade;
                                Buecher.Keys.Append(key, ADOX.KeyTypeEnum.adKeyForeign, null/*Type.Missing*/, null, null);
                    
                    //Hinzufügen der Buecher + Referenz
                                catalog.Tables.Append(Buecher);
                    Gruß
                    Tino
                    Ich habs gleich!
                    ... sagte der Programmierer.

                    Comment


                    • #11
                      Warum um himmelswillen willst Du denn in C++ programmieren? C++ ist ja gut und schön, aber einfach unnötig kompliziert und fehleranfällig. C# ist von C++ ein kleiner Schritt, aber sehr viel einfacher zu programmieren.
                      Trotzdem denke ich dass Du sämtliche Klassen auch unter Managed C++ verwenden. Mit DataSets habe ich so etwas schon mal gemacht und das hat wunderbar funktioniert.

                      Comment


                      • #12
                        Hallo,

                        nochmals vielen Dank für eure Antworten!!

                        @Tino - ich habs ausprobiert - die Exception entsteht aber leider immer noch.

                        @fanderlf - naja C++ kann ich und ich dachte damit fällt mir der Einstieg in Datenbanken leichter als wenn ich auch noch eine neue Programmiersprache lerne. In gewisserweise ist C++ und C# sehr ähnlich aber mit manchen Programmierkonstrukten bei C# bin ich noch gar nicht vertraut. Z.B. hab ich die Zeile key.Columns["AuthorID"].RelatedColumn = "ID"; einfach aus dem Buch übernommen - als C++ Programmierer finde ich sie aber etwas merkwürdig - kann ich bei C# auch Strings als eine Art Index für ein Array verwenden? Außerdem gibts doch bei C# keine Templates, oder? (irgendwie hab ich sowas in Erinnerung mal gehört zu haben).
                        Wenn ADO.NET dann genauso einfach mit C++ funktioniert wie mit C# dachte ich nehm ich lieber C++^^. Und wegen der Sicherheit: Wenn du meinst das man leicht ein Speicherleck bekommt weil man delete vergessen hat, dann gibt es durch .Net ja jetzt den gcnew-Befehl welcher dieses Problem beseitigt. Zugriffsverletzungen lösen an sich auch eine Exception aus, sodass sie schnell entdeckt werden. Oder warum ist C++ so unsicher?

                        Viele Grüße

                        Andreas

                        Comment


                        • #13
                          kann ich bei C# auch Strings als eine Art Index für ein Array verwenden?
                          Na klar. Hier wird vermutlich aber Properties eine irgendwie geartete Collection sein. ADOX war ja wenn ich das richtig in Erinnerung habe irgendein COM Zeugs.

                          Außerdem gibts doch bei C# keine Templates, oder?
                          Generics sind so ähnlich.

                          Wenn du meinst das man leicht ein Speicherleck bekommt weil man delete vergessen hat, dann gibt es durch .Net ja jetzt den gcnew-Befehl welcher dieses Problem beseitigt.
                          Nur zur Klarstellung. Du kannst nicht einfach beliebig zwischen new und gcnew wechseln. Wenn du in C++/CLR eine .Net Klasse benutzt dann geht nur ein gcnew. Wenn du z.B. irgendwas klassisches aus der STL verwendest nur new. Du bekommst keine garbage Collection für c++ Typen geschenkt nur für .NET Typen. Da ADOX kein .NET ist wird da gcnew wohl nicht funktionieren.

                          Comment


                          • #14
                            Hallo,
                            Nur zur Klarstellung. Du kannst nicht einfach beliebig zwischen new und gcnew wechseln. Wenn du in C++/CLR eine .Net Klasse benutzt dann geht nur ein gcnew. Wenn du z.B. irgendwas klassisches aus der STL verwendest nur new. Du bekommst keine garbage Collection für c++ Typen geschenkt nur für .NET Typen. Da ADOX kein .NET ist wird da gcnew wohl nicht funktionieren.
                            Achso ok - muss zugeben das war mir bisher noch nicht so klar - hab aber auch erst vor ein paar Wochen angefangen mich mit .Net zu beschäftigen.
                            Habe mir gerade einen Artikel über Collections durchgelesen - scheint ja ein sehr nützliches Konstrukt zu sein.

                            Nochmals vielen Dank.

                            Andreas

                            Comment


                            • #15
                              Also wenn man so etwas, gerade als C++ Programmierer, nicht liebt, dann weiss ich nicht xD

                              [highlight=c#]
                              List<String> myStrings = new List<String>(); //das wären die Generics (Templates) - für String kannst Du jede Klasse verwenden

                              foreach(String s in myStrings)
                              {
                              //mach was mit s
                              }
                              [/highlight]

                              C# ist wirklich eine tolle Sprache das da oben ist erst der Anfang. Wenn Du dann noch LINQ dazu nimmst wirds genial

                              Comment

                              Working...
                              X