[英]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時只有兩個關鍵缺陷:
插入將失敗,並顯示錯誤“缺少分號(;)”。 這是因為進行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.