使用LINQ和C#查询Microsoft Access MDB数据库

时间:2008-11-17 15:02:10

标签: c# linq ms-access

我有一个* .MDB数据库文件,我想知道是否有可能或建议在C#中使用LINQ来对抗它。我也想知道一些简单的例子会是什么样的。

我对LINQ知之甚少,但我对此任务的要求非常简单(我相信)。用户将传递给Microsoft Access MDB数据库的文件路径,我想使用LINQ将行添加到数据库中的一个表。

6 个答案:

答案 0 :(得分:14)

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

开箱即用,MS没有制作一个。可能有第三方。

答案 1 :(得分:13)

实际上我最近(今天)发现您可以使用LinqToSql访问Access数据库。它必须是2002或更新的格式,您将无法将表拖放到datacontext中,因此可以在dbml中手动创建对象,也可以使用SQL Server Migration for Access将其移动到sql server和然后拖放你想要的一切。当您想要实际创建上下文时,将其传递给OleDbConnection。在OleDbConnection上使用标准的Jet.OLEDB.4.0连接字符串,你很高兴。不确定这可能会产生的限制。我刚做了一个快速的样本并且没有问题就做了OrderBy。

答案 2 :(得分:7)

我写了一个小样本程序来测试大卫的回答。您需要创建一个访问数据库并手动创建Linq-to-SQL的DBML,因为您无法拖放它们。

插入失败,引用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();
            }
        }
    }
}

答案 3 :(得分:1)

您可以使用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);

答案 4 :(得分:0)

LINQ to SQL仅适用于SQL Server数据库。您需要的是Microsoft实体框架。这使得面向对象访问您的mdb。从这里你可以运行LINQ查询。

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

答案 5 :(得分:0)

我已经在很多论坛上看到了很多这个问题。我试了一下,对于那些一直在看它的人来说,这是一个完整的答案。

LinQ不是为Access做的。但是,许多查询将与Access一起使用,包括删除过程。因此,据我所知,使用Access时只有两个关键缺陷:

  1. 无法保存数据。
  2. 无法将对象拖放到dbml
  3. 插入将失败并显示错误&#34;缺少分号(;)&#34;。这是因为LinQ保存程序用于保存数据并检索一次保存的记录的主键ID。我们知道您无法在Access中执行多个SQL语句,因此这就是失败的原因。

    更新将失败并显示错误&#34;记录未找到&#34;。更新过程将导致查找要更新的记录然后更新它。我不知道为什么它找不到它,正常的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

    您必须手动将数据对象添加到dbml,因为在使用Access时无法拖放。另请注意,您必须在属性窗口中正确设置字段的所有属性。添加字段时未设置多个属性。

    enter image description here

    保存代码

      

    公共函数SaveAccountType(可选ByVal类型为String =   &#34;关闭&#34;)作为布尔

        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的开销,导致Insert无法使用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访问!快乐的编码:)