2008-11-17 63 views
36

Tôi có tệp cơ sở dữ liệu * .MDB và tôi tự hỏi nếu có thể hoặc được khuyến nghị làm việc với LINQ trong C#. Tôi cũng tự hỏi một số ví dụ đơn giản sẽ như thế nào.Truy vấn Cơ sở dữ liệu MDB của Microsoft Truy cập bằng LINQ và C#

Tôi không biết nhiều về LINQ, nhưng yêu cầu của tôi đối với tác vụ này khá đơn giản (tôi tin). Người dùng sẽ chuyển cho tôi đường dẫn tệp tới cơ sở dữ liệu Microsoft Access MDB và tôi muốn sử dụng LINQ để thêm hàng vào một trong các bảng trong cơ sở dữ liệu.

+0

bạn có thực sự tìm một nhà cung cấp để làm việc với ACCESS không? –

+1

Không, tôi đã quyết định làm điều đó một cách nhàm chán mà không cần LINQ to SQL. –

Trả lời

14

Điều bạn muốn là nhà cung cấp LINQ to ODBC hoặc nhà cung cấp LINQ to JET/OLEDB.

Hết hộp, MS không tạo. Có thể có một bên thứ ba làm.

+0

Tôi hiểu đây là một chủ đề cũ, nhưng tôi đã tạo ra một thư viện giống như EntityFramework một vài năm trở lại, có thể cho phép bạn sử dụng LINQ để truy cập trực tiếp MDB. Nó không phải là tính năng hoàn chỉnh, (cập nhật các thực thể chưa được hỗ trợ tốt) nhưng lấy các hàng của bảng khi các đối tượng hoạt động tốt https://accesstolinq.codeplex.com/ – EnderWiggin

0

LINQ to SQL chỉ hoạt động đối với cơ sở dữ liệu SQL Server. Những gì bạn cần là Microsoft Entity Framework. Điều này làm cho truy cập hướng đối tượng vào mdb của bạn. Từ đó bạn có thể chạy các truy vấn LINQ.

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

+5

Làm thế nào để sử dụng trình thiết kế đối với MDB? –

+4

sory nhưng EF không kết nối với MDB –

+11

Tại sao điều này sẽ tăng lên khi liên kết không sao lưu câu trả lời? – fuzz

13

Thật sự tôi thời gian gần đây (hôm nay) phát hiện ra rằng bạn có thể truy cập vào một cơ sở dữ liệu Access với LinqToSql. Nó phải ở định dạng 2002 hoặc mới hơn, bạn sẽ không thể kéo và thả các bảng vào datacontext của bạn để tạo thủ công các đối tượng trong dbml của bạn hoặc bạn có thể sử dụng SQL Server Migration cho Access để di chuyển nó sang máy chủ sql và sau đó kéo và thả tất cả những gì bạn muốn. Khi bạn muốn thực sự tạo ra bối cảnh vượt qua nó một OleDbConnection. Sử dụng chuỗi kết nối chuẩn Jet.OLEDB.4.0 của bạn trên OleDbConnection và bạn tốt để sử dụng. Bạn không chắc chắn về giới hạn này. Tôi vừa làm một mẫu nhanh và đã làm một OrderBy mà không có vấn đề gì.

+1

và đừng quên đổi tên TableAttributes trong designer.cs không có tên chủ sở hữu (ví dụ: đổi tên dbo.Articles thành Bài viết) – Gregoire

+0

Nó bị tê liệt lúc tốt nhất - cố gắng chạy một chèn đã cho tôi 'Thiếu dấu chấm phẩy (;) ở cuối câu lệnh SQL.' – jocull

+0

Vâng, tôi đã làm xong nó một lần, bạn có thể sử dụng truy vấn SELECT ra khỏi hộp, nhưng khá nhiều bất cứ điều gì khác sẽ phải được định nghĩa trong mã như một lệnh. Đó là rất nhiều công việc, nhưng vẫn tốt hơn làm tất cả bằng tay. –

1

Bạn có thể sử dụng Tập dữ liệu. Có phần mở rộng LINQ sẽ cho phép bạn truy vấn dữ liệu với tất cả những gì tốt đẹp LINQ mà chúng tôi đã trở thành sử dụng để :)

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

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

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

Tôi đã viết một chương trình mẫu nhỏ để kiểm tra điều này với câu trả lời của David. Bạn sẽ cần tạo cơ sở dữ liệu truy cập và tạo DBML theo cách thủ công cho Linq-to-SQL, vì bạn không thể kéo 'n thả chúng.

Chèn không thành công, trích dẫn Missing semicolon (;) at end of SQL statement. nhưng các truy vấn dường như không hoạt động.

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

Tôi đã thấy câu hỏi này rất nhiều và trong một số diễn đàn. Tôi đã đi vào nó và đây là một câu trả lời hoàn chỉnh cho những người đã nhìn vào nó.

LinQ không được tạo cho Access. Tuy nhiên, nhiều truy vấn sẽ làm việc với Access, bao gồm cả thủ tục xóa. Vì vậy, theo tôi, chỉ có 2 thiếu sót quan trọng khi làm việc với Access, là:

  1. không thể lưu dữ liệu.
  2. không thể kéo và thả các đối tượng vào dbml

Insert sẽ thất bại với lỗi "thiếu dấu chấm phẩy (;)". Điều này là do quy trình lưu LINQ đã được thực hiện để lưu dữ liệu và truy xuất ID khóa chính của bản ghi được lưu trong một lần. Chúng tôi biết rằng bạn không thể thực hiện nhiều câu lệnh SQL trong Access, vì vậy đó là lý do cho sự thất bại đó.

Cập nhật sẽ không thành công với lỗi "không tìm thấy bản ghi".Một thủ tục cập nhật sẽ là nguyên nhân tìm kiếm bản ghi được cập nhật rồi cập nhật nó. Tôi không thể nói tại sao nó sẽ không tìm thấy nó, khi bình thường LinQ truy vấn để tìm một hồ sơ hoạt động tốt.

Vì có rất nhiều lợi ích khi sử dụng LINQ, tôi đã tìm ra cách giải quyết sự thiếu hụt, đồng thời tận hưởng những lợi ích khác trong suốt quá trình đăng ký của tôi. Đây là cách (NB: Mã của tôi nằm trong VB.net, nhưng bạn có thể chuyển đổi nếu cần):

Tạo lớp LINQ to SQL (.dbml) để quản lý LINQ của bạn dựa vào cơ sở dữ liệu truy cập và cách quản lý thủ tục lưu của bạn. Dưới đây là các thủ tục đầy đủ về những gì tôi đã tạo và bây giờ tôi làm việc với LINQ để truy cập mà không có bất kỳ vấn đề nào:

Thêm một DataGridView vào biểu mẫu. Thêm nút cho Add, Edit & Xóa

enter image description here

Mã để điền vào lưới:

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

Mã để thiết lập contro l giá trị

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

Bạn sẽ có thêm các đối tượng dữ liệu vào dbml bằng tay kể từ khi bạn không có thể kéo và thả khi sử dụng Access. Cũng lưu ý rằng bạn sẽ phải thiết lập tất cả các thuộc tính của các trường một cách chính xác trong các cửa sổ thuộc tính. Một số thuộc tính không được đặt khi bạn thêm các trường.

enter image description here

Mã để Lưu

Công Chức năng SaveAccountType (Không bắt buộc ByVal loại 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 

Bây giờ thay thế hai dòng sau:

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

với một cái gì đó như thế này:

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

Phần cuối cùng của mã trên là những gì được bạn ID của hồ sơ lưu. Cá nhân, tôi thường làm cho nó một lựa chọn, bởi vì tôi không cần nó trong hầu hết các trường hợp, vì vậy tôi không cần phải thêm chi phí đó để lấy lại dữ liệu mỗi lần lưu một bản ghi, tôi rất vui khi biết bản ghi đã được lưu.

Đó là phí được thêm vào LINQ, điều này làm cho Chèn không thành công với Access. Có thực sự cần thiết để có nó? Tôi không nghĩ vậy.

Bạn có thể đã lưu ý rằng tôi thường đặt các quy trình Cập nhật và Chèn cùng nhau, để tiết kiệm thời gian cho tôi và đã giải quyết cả hai thủ tục Cập nhật Insert & trong một lần.

Mã cho Delete:

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 

Bây giờ bạn có thể thưởng thức LINQ để truy cập! Vui lòng mã hóa :)

Các vấn đề liên quan