it-swarm.com.de

Abfrage der Microsoft Access-MDB-Datenbank mit LINQ und C #

Ich habe eine * .MDB-Datenbankdatei, und ich frage mich, ob es möglich oder empfohlen ist, dagegen mit LINQ in C # zu arbeiten. Ich frage mich auch, wie einige einfache Beispiele aussehen würden.

Ich weiß nicht viel über LINQ, aber meine Anforderungen an diese Aufgabe sind ziemlich einfach (glaube ich). Der Benutzer wird mir einen Dateipfad an die Microsoft Access MDB-Datenbank übergeben, und ich möchte LINQ verwenden, um einer Tabelle in der Datenbank Zeilen hinzuzufügen.

36
Matthew Ruston

Sie möchten einen LINQ to ODBC Provider oder einen LINQ to JET/OLEDB-Provider.

MS macht aus dem Kasten keinen. Es kann eine dritte Partei geben, die dies tut.

14
FlySwat

Eigentlich habe ich kürzlich (heute) festgestellt, dass Sie mit LinqToSql auf eine Access-Datenbank zugreifen können. Das Format muss im Format von 2002 oder neuer sein. Sie können die Tabellen nicht per Drag & Drop in Ihren Datenkontext ziehen, sodass Sie die Objekte entweder manuell in Ihrer dbml erstellen oder SQL Server Migration for Access verwenden, um sie auf einen SQL-Server zu verschieben Ziehen Sie dann alles, was Sie möchten. Wenn Sie den Kontext tatsächlich erstellen möchten, übergeben Sie ihm eine OleDbConnection. Verwenden Sie Ihre standardmäßige Jet.OLEDB.4.0-Verbindungszeichenfolge für die OleDbConnection, und Sie können loslegen. Nicht sicher über die Einschränkungen, die sich daraus ergeben können. Ich habe nur ein kurzes Muster gemacht und ein OrderBy ohne Probleme gemacht.

13
David

Ich habe ein kleines Beispielprogramm geschrieben, um das mit Davids Antwort zu testen. Sie müssen eine Zugriffsdatenbank erstellen und DBML manuell für Linq-to-SQL erstellen, da Sie sie nicht per Drag & Drop ziehen können.

Einfügungen schlagen fehl, zitieren Missing semicolon (;) at end of SQL statement., aber Abfragen scheinen gut zu funktionieren.

Access database tables for Program

using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using Linq2Access.Data;

namespace Linq2Access
{
    class Program
    {
        static readonly string AppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        static readonly string DbPath = Path.Combine(AppPath, "Data", "database.accdb");
        static readonly string DbConnString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + DbPath + "';Persist Security Info=False;";

        static void Main(string[] args)
        {
            if (!File.Exists(DbPath))
                throw new Exception("Database file does not exist!");

            using (OleDbConnection connection = new OleDbConnection(DbConnString))
            using (DataRepositoryDataContext db = new DataRepositoryDataContext(connection))
            {
                List<dbProject> projects = new List<dbProject>();
                for (int i = 1; i <= 10; i++)
                {
                    dbProject p = new dbProject() { Title = "Project #" + i };
                    for (int j = 1; j <= 10; j++)
                    {
                        dbTask t = new dbTask() { Title = "Task #" + (i * j) };
                        p.dbTasks.Add(t);
                    }
                    projects.Add(p);
                }

                try
                {
                    //This will fail to submit
                    db.dbProjects.InsertAllOnSubmit(projects);
                    db.SubmitChanges();
                    Console.WriteLine("Write succeeded! {0} projects, {1} tasks inserted",
                                        projects.Count,
                                        projects.Sum(x => x.dbTasks.Count));
                }
                catch(Exception ex)
                {
                    Console.WriteLine("Write FAILED. Details:");
                    Console.WriteLine(ex);
                    Console.WriteLine();
                }

                try
                {
                    //However, if you create the items manually in Access they seem to query fine
                    var projectsFromDb = db.dbProjects.Where(x => x.Title.Contains("#1"))
                                                        .OrderBy(x => x.ProjectID)
                                                        .ToList();

                    Console.WriteLine("Query succeeded! {0} Projects, {1} Tasks",
                                        projectsFromDb.Count,
                                        projectsFromDb.Sum(x => x.dbTasks.Count));
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Query FAILED. Details:");
                    Console.WriteLine(ex);
                    Console.WriteLine();
                }

                Console.WriteLine();
                Console.WriteLine("Press any key to continue...");
                Console.ReadKey();
            }
        }
    }
}
7
jocull

Sie können ein DataSet verwenden. Es gibt Linq-Erweiterungen, mit denen Sie die Daten mit all der LINQ-Güte abfragen können, die wir verwendet haben :)

eICATDataSet.ICSWSbuDataTable tbl = new eICATDataSet.ICSWSbuDataTable();

ICSWSbuTableAdapter ta = new ICSWSbuTableAdapter();
ta.Fill(tbl);

var res = tbl.Select(x => x.ProcedureDate.Year == 2010);
1
Quinten Miller

LINQ to SQL funktioniert nur für SQL Server-Datenbanken. Was Sie brauchen, ist das Microsoft Entity Framework. Dies ermöglicht einen objektorientierten Zugriff auf Ihre MDB. Von hier aus können Sie LINQ-Abfragen ausführen.

http://msdn.Microsoft.com/de-de/library/aa697427(vs.80).aspx

0
GeekyMonkey

Ich habe diese Frage viel und in mehreren Foren gesehen. Ich habe es ausprobiert und hier ist eine vollständige Antwort für diejenigen, die es gesehen haben.

LinQ wurde nicht für den Zugriff erstellt. Viele der Abfragen funktionieren jedoch mit Access, einschließlich Löschverfahren. Meiner Meinung nach gibt es nur zwei entscheidende Mängel bei der Arbeit mit Access, nämlich:

  1. daten können nicht gespeichert werden.
  2. objekte können nicht auf die DB gezogen werden

Einfügen schlägt fehl mit dem Fehler "fehlendes Semikolon (;)". Dies liegt daran, dass das LinQ-Speicherverfahren zum Speichern von Daten und zum Abrufen der Primärschlüssel-ID des in einem Durchgang gespeicherten Datensatzes ausgeführt wurde. Wir wissen, dass Sie nicht mehrere SQL-Anweisungen in Access ausführen können. Dies ist der Grund für diesen Fehler.

Update schlägt fehl mit dem Fehler "Datensatz nicht gefunden". Bei einem Aktualisierungsvorgang wird der Datensatz nach Aktualisierungen gesucht und anschließend aktualisiert. Ich kann nicht sagen, warum es nicht gefunden wird, wenn eine normale LinQ-Abfrage zum Suchen eines Datensatzes einwandfrei funktioniert.

Da LinQ so viele Vorteile bietet, habe ich herausgefunden, wie Sie den Mangel umgehen können, während Sie die anderen Vorteile in meiner Anwendung nutzen können. So (NB: Meine Codes befinden sich in VB.net, können aber bei Bedarf konvertiert werden):

Erstellen Sie die LinQ-to-SQL-Klasse (.dbml), um LinQ anhand der Zugriffsdatenbank zu verwalten und die Speichervorgänge zu verwalten. Nachfolgend finden Sie die vollständigen Abläufe von dem, was ich erstellt habe, und ich arbeite jetzt problemlos mit LinQ to Access:

Fügen Sie eine DataGridView in einem Formular hinzu. Fügen Sie Schaltflächen für Hinzufügen, Bearbeiten und Löschen hinzu

 enter image description here

Code zum Ausfüllen des Gitters:

Private Sub ResetForm()

    Try

        Using db As New AccessDataClassesDataContext(ACCCon)

            Dim rows = (From row In db.AccountTypes
                        Where row.AccountTypeID > 1
                        Order By row.AccountTypeID Ascending
                        Select row).ToList()
            Me.DataGridView1.DataSource = rows

        End Using

    Catch ex As Exception
        MessageBox.Show("Error: " & vbCr & ex.ToString, "Data Error", MessageBoxButtons.OK)
    End Try

End Sub

DetailForm

 enter image description here

Code zum Einstellen der Steuerwerte

Private Sub ResetForm ()

    Try

        If _accountTypeID = 0 Then
            Exit Sub
        End If


        Using db As New AccessDataClassesDataContext(ACCCon)

            'Dim rows = (From row In db.AccountTypes
            '            Where row.AccountTypeID = _accountTypeID
            '            Order By row.AccountTypeID Ascending
            '            Select row.AccountTypeID, row.AccountType, row.LastUpdated).ToList()
            Dim rows = (From row In db.AccountTypes
                        Where row.AccountTypeID = _accountTypeID
                        Select row).ToList()

            For Each s In rows

                Me.AccountTypeIDTextBox.Text = s.AccountTypeID
                Me.myGuidTextBox.Text = s.myGuid
                Me.AccountTypeTextBox.Text = s.AccountType
                Me.AcHeadIDTextBox.Text = s.AcHeadID
                Me.DescriptionTextBox.Text = s.Description
                Me.LastUpdatedDateTimePicker.Value = s.LastUpdated

            Next

        End Using

    Catch ex As Exception

    End Try

End Sub

LinQToSQLClass

Sie müssen die Datenobjekte manuell zur Datenbank hinzufügen, da Sie bei Verwendung von Access kein Drag & Drop durchführen können. Beachten Sie auch, dass Sie alle Eigenschaften der Felder in den Eigenschaftsfenstern richtig einstellen müssen. Mehrere Eigenschaften werden nicht festgelegt, wenn Sie die Felder hinzufügen.

 enter image description here

Code zum Speichern

Öffentliche Funktion SaveAccountType (optionaler ByVal-Typ As String = "Close") As Boolean

    Dim success As Boolean = False
    Dim row As New AccountType

    Using db As New AccessDataClassesDataContext(ACCCon)

        If _accountTypeID > 0 Then

            row = (From r In db.AccountTypes
                   Where r.AccountTypeID = _accountTypeID).ToList()(0)

            If String.IsNullOrEmpty(row.AccountTypeID) Then
                MessageBox.Show("Requested record not found", "Update Customer Error")
                Return success
            End If

        End If

        Try

            With row
                .myGuid = Me.myGuidTextBox.Text
                .AccountType = Me.AccountTypeTextBox.Text
                .Description = Me.DescriptionTextBox.Text
                .AcHeadID = Me.AcHeadIDTextBox.Text
                .LastUpdated = Date.Parse(Date.Now())
            End With


            If _accountTypeID = 0 Then db.AccountTypes.InsertOnSubmit(row)
            db.SubmitChanges()

            success = True

        Catch ex As Exception
            MessageBox.Show("Error saving to Customer: " & vbCr & ex.ToString, "Save Data Error")
        End Try

    End Using

    Return success

End Function

Ersetzen Sie nun diese beiden Zeilen:

            If _accountTypeID = 0 Then db.AccountTypes.InsertOnSubmit(row)
            db.SubmitChanges()

mit so etwas wie:

        Dim cmd As IDbCommand

        cmd = Me.Connection.CreateCommand()
        cmd.Transaction = Me.Transaction
        cmd.CommandText = query

        If myGuid.Trim.Length < 36 Then myGuid = UCase(System.Guid.NewGuid.ToString())
        cmd.Parameters.Add(New OleDbParameter("myGuid", row.myGuid))
        cmd.Parameters.Add(New OleDbParameter("AccountType", row.AccountType))
        cmd.Parameters.Add(New OleDbParameter("Description", row.Description))
        cmd.Parameters.Add(New OleDbParameter("AcHeadID", row.AcHeadID))
        cmd.Parameters.Add(New OleDbParameter("LastUpdated", Date.Now))
        If AccountTypeID > 0 Then cmd.Parameters.Add(New OleDbParameter("AccountTypeID", row.AccountTypeID))

        If Connection.State = ConnectionState.Closed Then Connection.Open()

        result = cmd.ExecuteNonQuery()

        cmd = Me.Connection.CreateCommand()
        cmd.Transaction = Me.Transaction
        cmd.CommandText = "SELECT @@IDENTITY"
        result = Convert.ToInt32(cmd.ExecuteScalar())

Der letzte Teil des obigen Codes enthält die ID des Datensatzes. Ich persönlich mache das normalerweise zu einer Option, weil ich es in den meisten Fällen nicht brauche, also muss ich nicht den zusätzlichen Aufwand hinzufügen, Daten abzurufen, wenn ein Datensatz gespeichert wird Datensatz wurde gespeichert.

Dies ist der zu LinQ hinzugefügte Aufwand, der dazu führt, dass Insert mit Access fehlschlägt. Ist es wirklich notwendig, es zu haben? Ich glaube nicht.

Möglicherweise haben Sie festgestellt, dass ich normalerweise meine Aktualisierungs- und Einfügungsprozeduren zusammengebaut habe, so dass ich Zeit einsparen und sowohl die Einfügungs- als auch die Aktualisierungsprozeduren auf einmal bearbeiten kann.

Code zum Löschen:

Private Sub DelButton_Click(sender As Object, e As EventArgs) Handles DelButton.Click
    Using db As New AccessDataClassesDataContext(ACCCon)

        Dim AccountTypeID As Integer = Me.DataGridView1.CurrentRow.Cells(0).Value
        Dim row = From r In db.AccountTypes Where r.AccountTypeID = AccountTypeID

        For Each detail In row
            db.AccountTypes.DeleteOnSubmit(detail)
        Next

        Try
            db.SubmitChanges()
        Catch ex As Exception
            ' Provide for exceptions.
            MsgBox(ex)
        End Try

    End Using

End Sub

Jetzt können Sie LinQ to Access genießen! Viel Spaß beim Codieren :)

0