Mit C# accdb Datenbank und ein bestimmtes Formular zu öffnen

  • C#

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von Mono.

    Mit C# accdb Datenbank und ein bestimmtes Formular zu öffnen

    Hi,
    ich bin noch ein ziemlicher Neuling, der sich gerade in das Thema "Programmierung mit C#" einarbeitet. Weiterhin kaue ich schon länger an meinem Problem rum, obwohl ich schon viel nach Lösungen gesucht habe. Folgende Ziele habe ich vor, die ich mit C# erreichen möchte:
    • Die Commandline zu zerpflücken, damit nur noch die Kundennummer übrig bleibt.
    • Eine accdb Datenbank zu öffnen.
    • Ein bestimmtes Formular zu öffnen.
    • Die Kundennummer in das Formular einfügen und ausführen.
    Die Commandline habe ich bereits erfolgreich gesplittet und die Kundennummer als globale Variable gespeichert. Jetzt habe ich zurzeit das Problem mit dem Öffnen der Datenbank.

    Folgende Möglichkeiten habe ich schon ausprobiert:
    • Process.Start -> Damit kann ich die DB zwar öffnen, aber soweit ich weiß, habe ich keine Möglichkeit auf ein bestimmtes Formular zu zugreifen. -> Scheidet also aus.
    • Über Access.Application -> Ich habe das zwar drin, aber es funktioniert nicht. Die Datenbank wird nicht aufgerufen. Dieser Weg wäre wohl am Besten um nachher ein Formular öffnen zu können.
    • Über OleDbConnection -> Hier wird zwar die Connection zur Datenbank hergestellt, aber Access wird nicht geöffnet. Habe ich hier etwas übersehen?
    Es geht jetzt erstmal nur um das Öffnen der DB. Wenn das klappt, so würde ich erstmal auf eigene Faust weiter versuchen das Formular zu öffnen.

    Anbei poste ich wohl am besten meinen kompletten Code rein. Falls ihr noch andere Verbesserungsvorschläge habt, so sind diese natürlich willkommen! Ich danke euch schon mal im Vorraus für eure Antworten.

    Grüße Stefan

    Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using System.Data.OleDb;
    7. using System.Diagnostics;
    8. using System.Windows.Forms;
    9. using Access = Microsoft.Office.Interop.Access;
    10. namespace ConnectTtoAccdb
    11. {
    12. class Program
    13. {
    14. public static string kundennr;
    15. static void Main(string[] args)
    16. {
    17. try
    18. {
    19. if (args.Length == 0) // Prüfen, ob Environment.CommandLine 0 Zeichen beinhaltet.
    20. {
    21. keineKundennr(); // Hat die Environment.CommandLine 0 Zeichen, so wird die Methode "keineKundennr" aufgerufen.
    22. }
    23. else // Falls nein, so gibt es eine Kundennr.
    24. {
    25. Console.WriteLine(Environment.CommandLine);
    26. Console.ReadLine();
    27. splittenCommandLine(); // Die Methode "splittenCommandLine" wird aufgerufen.
    28. //openAccess(); // Wurde nur auskommentiert, da die Methode nicht die DB aufruft.
    29. openDB();
    30. }
    31. }
    32. catch (Exception ex) // Fehler wird abgefangen.
    33. {
    34. Console.WriteLine(ex.Message);
    35. Console.WriteLine("Die Länge der Kundennummer ist unter 0");
    36. }
    37. }
    38. private static void keineKundennr()
    39. {
    40. string myMeldung = "Die Kommandozeile ist leer.";
    41. string appName = AppDomain.CurrentDomain.FriendlyName;
    42. Console.WriteLine("{0}{1}{1}{2}{1}Es wird eine Telefonnummer oder eine Kundennummer benötigt.", appName, Environment.NewLine, myMeldung); // Bei keiner Kundennr wird diese Zeile ausgegeben.
    43. Console.ReadLine();
    44. }
    45. private static void splittenCommandLine()
    46. {
    47. string commandLine = Environment.CommandLine; // Die commandLine wird als String abgespeichert.
    48. string substringAbBindestrich = commandLine.Substring(commandLine.LastIndexOf('-') + 1); // Der String wird nach dem Bindestrich aufgetrennt.
    49. Console.WriteLine(substringAbBindestrich); // Der String wird (alles nach dem Bindestrich) ausgegeben.
    50. kundennr = substringAbBindestrich.Substring(substringAbBindestrich.LastIndexOf(':') + 1); // Der String wird nach dem Doppelpunkt aufgetrennt.
    51. Console.WriteLine(kundennr); // Der String wird (alles nach dem Doppelpunkt) ausgegeben.
    52. }
    53. public static void openAccess()
    54. {
    55. Access.Application oAccess = null;
    56. oAccess = new Access.ApplicationClass();
    57. oAccess.OpenCurrentDatabase("C:\\Users\\sf\\Desktop\\MeinTest.accdb", true);
    58. // oAccess.DoCmd.OpenForm("MSB", Access.AcFormView.acNormal, System.Reflection.Missing.Value,"[Ku_Nr]"); // Mein 1. Versuch um ein Formular zu öffnen. Auskommentiert um zu testen, ob die DB wenigstens aufgerufen wird.
    59. }
    60. public static void openDB()
    61. {
    62. string connetionString = null;
    63. OleDbConnection cnn;
    64. connetionString = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source = C:\\Users\\sf\\Desktop\\MeinTest.accdb";
    65. cnn = new OleDbConnection(connetionString);
    66. try
    67. {
    68. cnn.Open();
    69. MessageBox.Show("Connection Open ! ");
    70. cnn.Close();
    71. }
    72. catch (Exception ex)
    73. {
    74. MessageBox.Show("Can not open connection ! ");
    75. }
    76. }
    77. }
    78. }

    Das sind 2 verschiedene Sachen:
    Zum einen ist das Office-InterOp, wenn du per c# Access ansteuern willst, dass Access ein bestimmtes UserForm öffnet.
    Kann ich nicht viel zu sagen, ausser, dass ich Office-InterOp von Excel und von Word her kenne, und zwar als sehr problematisch, insbesondere, was die ResourcenBereinigung angeht.
    Bei Excel zB. muss man sehr geschickt vorgehen, sonst bleibt nach dem InterOp-Zugriff ein unsichtbares Excel im Speicher hängen, und sabotiert eine normale Nutzung von Excel.

    Das andere ist, auf das Access-Frontend komplett zu verzichten, und die accdb einfach nur als Datenbank zu nutzen, also als BackEnd. Und das FrontEnd dann in c# zu programmieren, mit eigenen Forms etc.. Hierfür wird OleDb verwendet.

    Also bereits die Formulierung "Öffnen der DB" ist zweideutig, und du müsstest entscheiden, welche Bedeutung du meinst.

    ErfinderDesRades schrieb:

    Das sind 2 verschiedene Sachen:
    Zum einen ist das Office-InterOp, wenn du per c# Access ansteuern willst, dass Access ein bestimmtes UserForm öffnet.
    Kann ich nicht viel zu sagen, ausser, dass ich Office-InterOp von Excel und von Word her kenne, und zwar als sehr problematisch, insbesondere, was die ResourcenBereinigung angeht.
    Bei Excel zB. muss man sehr geschickt vorgehen, sonst bleibt nach dem InterOp-Zugriff ein unsichtbares Excel im Speicher hängen, und sabotiert eine normale Nutzung von Excel.

    Das andere ist, auf das Access-Frontend komplett zu verzichten, und die accdb einfach nur als Datenbank zu nutzen, also als BackEnd. Und das FrontEnd dann in c# zu programmieren, mit eigenen Forms etc.. Hierfür wird OleDb verwendet.

    Also bereits die Formulierung "Öffnen der DB" ist zweideutig, und du müsstest entscheiden, welche Bedeutung du meinst.


    Endlich kenne ich jetzt den Unterschied zwischen InterOp und OleDb! Danke :) Also ich wollte nicht auf die Access-Frontend verzichten, weshalb ich wohl dann über InterOp gehen müsste. Sprich die Methode "openAccess()" wäre dann wohl die Richtige. Kennst du eine Seite, welche das Office-InterOp näher erläutert?
    ähm - es ist ein bischen mehr als ein Unterschied. Für einen Unterschied müsste es ja Gemeinsamkeiten geben, aber InterOp ist etwas komplett anderes als Datenbank-Zugriffe.

    Oledb ist eine Art (von mehreren) des Datenbank-Zugriffs, und mit DB-Zugriff ist gemeint: Zugriff auf ein Db-Backend.

    Office-Interop ist eine Fernsteuerung, und zwar Fernsteuerung von dafür geeigneten Anwendungen - meist Office - wie Excel, Word, Access, PowerPoint, aber es gibt noch mehr, auch anderer Anbieter als Microsoft.


    Meza100 schrieb:

    Kennst du eine Seite, welche das Office-InterOp näher erläutert?
    nö, aber vlt. weiß jmd anners noch was.

    Ansonsten googeln.
    Generell muss man bei InterOp als erstes Verweise setzen auf besondere Bibliotheken, die das Objektmodell der fernzusteuernden Anwendung offenlegen.
    Jo, und dann musste dich in dieses Objektmodell einarbeiten.
    Als erstes brauchst du eine Referenz auf das COM Objekt MIcrosoft Acces 14.0 Object Library(JE nach Version ggf.12,11,). In deinem Projekt zu finden unter Reference->Add Reference und COM.
    Dann fügst du folgenden Code in deine Form:

    C#-Quellcode

    1. Microsoft.Office.Interop.Access.Application oAccess = null;
    2. oAccess = new Microsoft.Office.Interop.Access.Application();
    3. oAccess.Visible = true; //auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    4. oAccess.OpenCurrentDatabase("D:\\database1.mdb", true); //pfad halt
    5. oAccess.DoCmd.OpenForm("Form1", //formname
    6. Microsoft.Office.Interop.Access.AcFormView.acNormal, //View
    7. System.Reflection.Missing.Value, //FilterName
    8. System.Reflection.Missing.Value, //WhereCondition
    9. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormReadOnly, //DataMode
    10. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, //WindowMode
    11. System.Reflection.Missing.Value); //OpenArgs


    //Edit: wegen den Instanzen die noch rennen usw.
    Im Normalfall sollte reichen (bei Beenden deiner Anwendung oder wenn du nix mehr mit dem COM Teil machst:

    C#-Quellcode

    1. oAccess.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveNone);
    2. oAccess = null;
    Das ist meine Signatur und sie wird wunderbar sein!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Mono“ ()

    Das ist entweder nicht dein Ernst, oder bedarf genauerer Erläuterung. Weil wenn ich mache, wie du sagst, kommt folgender Müll dabei heraus:

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Windows.Forms;
    8. namespace AsyncSamplesCs {
    9. public partial class Form1 : Form {
    10. public Form1() {
    11. InitializeComponent();
    12. }
    13. Microsoft.Office.Interop.Access.Application oAccess = null;
    14. // Start a new instance of Access for Automation:
    15. oAccess = new Microsoft.Office.Interop.Access.Application();
    16. oAccess.Visible = true; //auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    17. oAccess.OpenCurrentDatabase("D:\\database1.mdb", true); //pfad halt
    18. oAccess.DoCmd.OpenForm("Form1", //formname
    19. Microsoft.Office.Interop.Access.AcFormView.acNormal, //View
    20. System.Reflection.Missing.Value, //FilterName
    21. System.Reflection.Missing.Value, //WhereCondition
    22. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormReadOnly, //DataMode
    23. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, //WindowMode
    24. System.Reflection.Missing.Value); //OpenArgs
    25. }
    26. }
    Er hat ja bereits eine Methode OpenAccess und sich den Code da oben iwie zusammengefriemelt. Daher traue ich ihm zu den Code in seine Methode einzufügen. Falls er mit der Antwort nicht klar kommt wird er das sicherlich kundtun. Hab eben gerade gesehen das er eh ein Consoleprojekt hat. Habe mir seinen Code nicht genau angeschaut und nur "using System.Windows.Forms;" gesehen und daher angenommen das er ein WinForm Projekt hat.

    ​jo, da ist jetzt der Threadersteller gefragt, wieviel davon ihm klar ist


    Genau so sehe ich das auch, also verstehe ich nicht wieso du das überhaupt kommentierst (zumal es inhaltlich nix beiträgt und nur auf meiner nicht ganz exakten Ausformulierung rumhackt).
    Das ist meine Signatur und sie wird wunderbar sein!
    Wenn man wirklich eine Officeanwendung fernsteuern muss, dann würde ich InterOp nicht direkt verwenden, denn die daraus erstellte Programme laufen nur mit genau dieser einen Officeversion, dessen Assembly eingebunden wurde und mit keiner anderen.
    Es gibt gute Wrapper um InterOp, die einem die Arbeit sowieso schon erleichtern und mit ihnen ist man idR auch nicht mehr abhängig von einer bestimmten Officeversion.

    Meine Empfehlung seit ein paar Jahren: netoffice.codeplex.com/
    @ Mono und ErfinderDesRades:
    Vielen Dank für eure Beiträge. Die Referenz wurde von mir schon bereits hinzugefügt. Leider hat es bis dahin noch nicht funktioniert. Wisst ihr, woran es lag, dass es nicht ging? Jetzt funktioniert es fast wie gewünscht :D

    Die Datenbank lässt sich öffnen und das Form öffnet sich auch. Jetzt muss ich nur noch die Where Condition richtig programmieren.

    Zum guten Schluss muss ich nur noch das komplette Programm nochmal verfeinern (mehr try-catch, schauen ob mehr Methoden sinnvoll wären, usw.).

    Ihr habt mir bisher großartig geholfen! Ich werde mich sicherlich nochmal melden, ob es sich mit der Where Condition geklappt hat ;)

    Danke und Grüße, Meza100

    @ Dksksm: Das ist kein Problem, da die Access Version überall gleich sind. Aber danke für den Hinweis! Somit muss ich mir das im Hinterkopf behalten, sofern wir mal die Access Version mal ändern sollten.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Meza100“ ()

    Mono schrieb:



    Es ging vermutlich die ganze Zeit nur war .visible auf false und daher hast es nicht gesehen.


    Du hast recht. Ich habe soeben das mal aus Neugier getestet. Da ich die Methode "oAccess.Visible" nicht in meinem Code hatte, hat er es auf false gelassen (was auch logisch ist). Es ist der Wahnsinn, was eine kleine Passage an Auswirkung haben kann. Danke für die Antwort.
    Das mit der Where Condition hat heute auch noch geklappt.

    Quellcode

    1. oAccess.DoCmd.OpenForm("MSB", // Formname
    2. Microsoft.Office.Interop.Access.AcFormView.acNormal, // View
    3. System.Reflection.Missing.Value, // FilterName
    4. "[Ku_Nr]=" + "'" + kundennr +"'", // Where Condition
    5. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormPropertySettings, // DataMode -> Property Settings, da im alten VB Code das so drinnen war.
    6. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, // WindowMode
    7. System.Reflection.Missing.Value); // OpenArgs


    Die Where Condition sollte nur für diejenigen dienen, die vllt. einen Anhaltspunkt für ihre Condition bräuchten ;)

    ebk schrieb:

    Du schreibts mit C#, nimmst aber nicht VS.NET, um das Frontend zu machen ?

    Wenn es dabei bleibt, dann nimm Netoffice, statt interop, es macht dich unabhängig von der jeweiligen Version.


    Da wir erstmal alle auf derselben Version sind, macht das mir nichts aus. Welche Vorteile bringt das noch mit?

    Weiterhin hätte ich noch eine Frage. Ich bin gerade dabei die Methode openAccess auf "openAccess" und "openForm" aufzusplitten. Sobald ich den Part ab "oAccess.DoCmd.OpenForm" in die Methode "openForm" einfüge, so findet er das Objekt oAccess nicht (was ja klar ist). Das Objekt wurde ja in openAccess deklariert.

    Gibt es eine Möglichkeit auf dieses Objekt (oAccess in openAccess) zu zugreifen?
    Das lässt sich am besten an einem Beispiel erläutern, welches du vorgibst.
    Weil ich hab ja keine Methode openAccess die ich aufsplitten könnte zu openAccess und openForm.

    Also wie sieht dein aktueller Code aus?

    Übrigens benutz bitte die richtigen Code-Tags, das würde deine Snippets wesentlich leserlicher machen. Evtl gugge auch
    das zeigt allerlei Möglichkeiten, die man hier hat.