。また、いくつかの簡単な例がどのように見えるかについても疑問に思っています。
LINQについてはあまり知りませんが、このタスクの要件は非常に単純です(信じています)。ユーザーは、Microsoft Access MDBデータベースへのファイルパスを渡すので、LINQを使用してデータベース内のテーブルの1つに行を追加したいと思います。
必要なのは、LINQ to ODBCプロバイダー、またはLINQ to JET/OLEDBプロバイダーです。
箱から出してすぐに、MSはそれを作りません。サードパーティが存在する可能性があります。
実際、最近(今日)LinqToSqlでAccessデータベースにアクセスできることを発見しました。 2002以降の形式である必要があります。テーブルをデータコンテキストにドラッグアンドドロップできないため、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.
を引用しますが、クエリは問題なく動作するようです。
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();
}
}
}
}
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);
LINQ to SQLは、SQL Serverデータベースでのみ機能します。必要なのは、Microsoft Entity Frameworkです。これにより、オブジェクト指向でmdbにアクセスできます。これから、LINQクエリを実行できます。
http://msdn.Microsoft.com/en-us/library/aa697427(vs.80).aspx
私はこの質問を何度も見ました。私はそれを試してみましたが、ここでそれを見ている人への完全な答えがあります。
LinQはAccess用に作成されていません。ただし、削除手順など、クエリの多くはAccessで機能します。ですから、私によると、Accessを使用するときの重大な欠陥は2つしかありません。
挿入は、エラー「セミコロン(;)がありません」で失敗します。これは、データを保存し、一度に保存されたレコードの主キーIDを取得するためにLinQの保存手順が作成されたためです。 Accessで複数のSQLステートメントを実行できないことがわかっているため、そのことが失敗の原因です。
更新はエラー「レコードが見つかりません」で失敗します。更新手順では、更新するレコードを探して更新します。レコードを見つけるための通常のLinQクエリが正常に機能する場合、なぜ見つからないのかわかりません。
LinQを使用することには非常に多くの利点があるため、アプリケーション全体で他の利点を享受しながら、不足を回避する方法を見つけました。これは次のとおりです(NB:私のコードは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
DetailForm
制御値を設定するコード
プライベートサブ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を使用するとドラッグアンドドロップできないため、dbmlにデータオブジェクトを手動で追加する必要があります。また、プロパティウィンドウでフィールドのすべてのプロパティを正しく設定する必要があることに注意してください。フィールドを追加すると、いくつかのプロパティが設定されません。
保存するコード
パブリック関数SaveAccountType(オプションのByVal type 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
次の2行を置き換えます。
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 to Accessをお楽しみください!ハッピーコーディング:)