簡體   English   中英

使用LINQ和C#查詢Microsoft Access MDB數據庫

[英]Query Microsoft Access MDB Database using LINQ and C#

我有一個* .MDB數據庫文件,我想知道是否有可能或建議使用C#中的LINQ來對付它。 我也想知道一些簡單的例子是什么樣子。

我對LINQ知之甚少,但是我對這項任務的要求非常簡單(我相信)。 用戶將向我傳遞一個指向Microsoft Access MDB數據庫的文件路徑,我想使用LINQ向數據庫中的一個表添加行。

您需要的是LINQ to ODBC提供程序或LINQ to JET / OLEDB提供程序。

開箱即用,MS卻一無所獲。 可能會有第三者參加。

實際上,我最近(今天)發現您可以使用LinqToSql訪問Access數據庫。 它必須采用2002或更高版本的格式,您將無法將表拖放到datacontext中,因此可以在dbml中手動創建對象,也可以使用SQL Server Migration for Access將其移動到sql服務器,並且然后拖放所有想要的內容。 當您要實際創建上下文時,將其傳遞給OleDbConnection。 在OleDbConnection上使用標准的Jet.OLEDB.4.0連接字符串,一切順利。 不確定是否會產生限制。 我只是做了一個快速的樣本,並做了一個OrderBy,沒有問題。

我寫了一個小樣本程序來用David的答案進行測試。 您將需要創建一個訪問數據庫並手動創建用於Linq-to-SQL的DBML,因為您不能將它們拖放。

插入失敗,並Missing semicolon (;) at end of SQL statement.援引Missing semicolon (;) at end of SQL statement. 但是查詢似乎還可以。

訪問程序的數據庫表

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

您可以使用數據集。 有linq擴展名,使您可以查詢我們已經習慣使用的所有LINQ優點的數據:)

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

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

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

LINQ to SQL僅適用於SQL Server數據庫。 您需要的是Microsoft實體框架。 這使您可以對mdb進行面向對象的訪問。 由此您可以運行LINQ查詢。

http://msdn.microsoft.com/zh-CN/library/aa697427(vs.80).aspx

我已經在很多論壇上看到了很多這個問題。 我做了一下,對於那些一直在看的人來說,這是一個完整的答案。

LinQ不是為Access設計的。 但是,許多查詢將與Access一起使用,包括刪除過程。 因此,根據我的觀點,使用Access時只有兩個關鍵缺陷:

  1. 無法保存數據。
  2. 無法將對象拖放到dbml上

插入將失敗,並顯示錯誤“缺少分號(;)”。 這是因為進行LinQ保存過程是為了保存數據並一次檢索保存的記錄的主鍵ID。 我們知道您不能在Access中執行多個SQL語句,所以這就是失敗的原因。

更新將失敗,並顯示錯誤“找不到記錄”。 更新過程將導致查找要更新的記錄,然后對其進行更新。 當普通的LinQ查詢來查找記錄時,我無法說出為什么找不到它。

因為使用LinQ有很多好處,所以我想出了解決該缺陷的方法,同時在整個應用程序中都享有其他好處。 這是這樣的(注意:我的代碼在VB.net中,但是如果需要可以轉換):

創建LinQ to SQL(.dbml)類以針對訪問數據庫管理LinQ,並提供一種管理保存過程的方法。 以下是我創建的全部過程,現在我可以使用LinQ to Access正常工作:

在窗體上添加一個DataGridView 添加按鈕進行添加,編輯和刪除

在此處輸入圖片說明

填充網格的代碼:

 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 

明細表

在此處輸入圖片說明

設置控制值的代碼

私人子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

您將必須手動將數據對象添加到dbml中,因為使用Access時無法拖放。 還要注意,您將必須在屬性窗口中正確設置字段的所有屬性。 添加字段時未設置幾個屬性。

在此處輸入圖片說明

保存代碼

公共函數SaveAccountType(可選ByVal類型,當String =“ Close”)為布爾值

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

上面代碼的最后一部分是讓您獲取已保存記錄的ID的方法。 就個人而言,我通常會選擇一個選項,因為在大多數情況下我都不需要它,因此我不需要添加每次保存記錄時都回取數據的開銷,我很高興知道記錄已保存。

那是增加到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訪問! 快樂的編碼:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM