Запрос базы данных Microsoft Access MDB с использованием LINQ и C # - PullRequest
36 голосов
/ 17 ноября 2008

У меня есть файл базы данных * .MDB, и мне интересно, можно ли или рекомендовать работать с ним, используя LINQ в C #. Мне также интересно, как бы выглядели некоторые простые примеры.

Я не знаю много о LINQ, но мои требования для этой задачи довольно просты (я считаю). Пользователь передаст мне путь к файлу базы данных Microsoft Access MDB, и я хотел бы использовать LINQ для добавления строк в одну из таблиц в базе данных.

Ответы [ 6 ]

14 голосов
/ 17 ноября 2008

Требуется поставщик LINQ to ODBC или поставщик LINQ to JET / OLEDB.

Из коробки MS не делает ни одного. Может быть третья сторона, которая делает.

13 голосов
/ 21 октября 2009

На самом деле я недавно (сегодня) обнаружил, что вы можете получить доступ к базе данных Access с LinqToSql. Он должен быть в формате 2002 или новее, вы не сможете перетаскивать таблицы в ваш текстовый текст, поэтому либо вручную создайте объекты в вашем dbml, либо вы можете использовать SQL Server Migration for Access, чтобы переместить его на сервер sql и затем перетащите все, что вы хотите. Если вы хотите создать контекст, передайте ему OleDbConnection. Используйте стандартную строку соединения Jet.OLEDB.4.0 на OleDbConnection, и все готово. Не уверен, что это может повлечь за собой ограничение. Я просто сделал быстрый пример и сделал OrderBy без проблем.

7 голосов
/ 08 марта 2013

Я написал небольшую примерную программу, чтобы проверить это с ответом Дэвида. Вам нужно будет создать базу данных доступа и вручную создать DBML для Linq-to-SQL, поскольку вы не можете перетаскивать их.

Вставки не выполняются, ссылаясь на Missing semicolon (;) at end of SQL statement., но кажется, что запросы работают нормально.

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();
            }
        }
    }
}
1 голос
/ 25 февраля 2010

Вы можете использовать DataSet. Существуют расширения linq, которые позволят вам запрашивать данные со всеми теми качествами LINQ, которыми мы стали пользоваться:)

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

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

var res = tbl.Select(x => x.ProcedureDate.Year == 2010);
0 голосов
/ 26 октября 2017

Я видел этот вопрос много раз и на нескольких форумах. Я попробовал, и вот полный ответ для тех, кто на это смотрел.

LinQ не был создан для доступа. Однако многие запросы будут работать с Access, включая процедуру удаления. Так что, по моему мнению, при работе с Access есть только два критических недостатка:

  1. невозможно сохранить данные.
  2. не в состоянии перетаскивать объекты в базу данных

Вставить не удастся с ошибкой «отсутствует точка с запятой (;)». Это связано с тем, что процедура сохранения LinQ была сделана для сохранения данных и получения идентификатора первичного ключа записи, сохраненной за один раз. Мы знаем, что вы не можете выполнять несколько операторов SQL в Access, поэтому это является причиной этой ошибки.

Обновление не будет выполнено с ошибкой «запись не найдена». Процедура обновления приведет к поиску обновленной записи и обновлению. Я не могу сказать, почему он не может его найти, когда обычный запрос LinQ для поиска записи работает нормально.

Поскольку использование LinQ дает много преимуществ, я понял, как обойти этот недостаток, и в то же время пользовался другими преимуществами в моем приложении. Вот как (NB: Мои коды находятся на VB.net, но вы можете конвертировать при необходимости):

Создайте класс LinQ to SQL (.dbml) для управления вашим LinQ по базе данных доступа и способ управления процедурой сохранения. Ниже приведены полные процедуры того, что я создал, и теперь я без проблем работаю с LinQ to Access:

Добавьте DataGridView в форму. Добавить кнопки для добавления, редактирования и удаления

enter image description here

Код для заполнения сетки:

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

Код для установки контрольных значений

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

Вам придется добавить объекты данных в базу данных вручную, поскольку вы не можете перетаскивать их при использовании Access. Также обратите внимание, что вам придется правильно настроить все свойства полей в окнах свойств. Некоторые свойства не устанавливаются при добавлении полей.

enter image description here

Код для сохранения

Открытая функция SaveAccountType (Необязательный тип ByVal As String = "Закрыть") Как логическое

    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

Теперь замените эти две строки:

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

с чем-то вроде этого:

        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())

Последняя часть кода выше - это то, что возвращает вам идентификатор сохраненной записи. Лично я обычно делаю эту опцию, потому что она мне не нужна в большинстве случаев, поэтому мне не нужно добавлять эти накладные расходы при извлечении данных каждый раз, когда запись сохраняется, я рад просто запись была сохранена.

Это накладные расходы, добавленные в LinQ, что приводит к сбою вставки с Access. Это действительно необходимо иметь? Я так не думаю.

Вы, возможно, заметили, что я обычно соединяю процедуры обновления и вставки, чтобы сэкономить время и иметь возможность одновременно выполнять процедуры вставки и обновления.

Код для удаления:

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

Теперь вы можете наслаждаться LinQ для доступа! Удачного кодирования:)

0 голосов
/ 17 ноября 2008

LINQ to SQL работает только для баз данных SQL Server. Что вам нужно, так это Microsoft Entity Framework. Это делает объектно-ориентированный доступ к вашему MDB. Отсюда вы можете запускать запросы LINQ.

http://msdn.microsoft.com/en-us/library/aa697427(vs.80).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...