[.net] 如何從Linq 2 SQL移動到Linq 2實體?


Answers

在EF中執行針對數據庫的SQL命令

using System.Data.EntityClient;
...
EntityConnection conn = new EntityConnection(myContext.Connection.ConnectionString);
conn.Open();
EntityCommand cmd = conn.CreateCommand();
cmd.CommandText = @"Select t.MyValue From MyEntities.MyTable As t";
var result = cmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);
result.Read();
var myValue = result.GetValue(0);
...
conn.Close();

命令文本在實體SQL中,與T-SQL不是100%相同的

Question

我想為想要從linq2sql轉移到linq2entities和ADO.net實體框架(在這裡稱為L2E)的人開始參考。 我不想討論哪一個更好。 我只是想為這兩個人想要從一個過渡到另一個創建一個差異列表。

基本的東西很簡單:刪除linq2sql數據類,添加ado.net模型(從數據庫創建)。 將“實體”重命名為以前的datacontext的名稱。

現在,差異。 例如, 要堅持(保存)L2S中的更改,我會使用:

using (MyDataClassesDataContext mydc = new MyDataClassesDataContext())
{
  // change data
  mydc.SubmitChanges();
}

在L2E中,這將不得不改為:

using (MyDataClassesDataContext mydc = new MyDataClassesDataContext())
{
  // change data
  mydc.SaveChanges();
}

第二個例子, 在L2S中插入一個新的記錄,你可以使用:

using (MyDataClassesDataContext mydc = new MyDataClassesDataContext())
{
  MyTable myRow = new MyTable();
  mydc.MyTable.InsertOnSubmit(myRow);
  mydc.SubmitChanges();
}

在L2E中,這將不得不改為:

using (MyDataClassesDataContext mydc = new MyDataClassesDataContext())
{
  MyTable myRow = new MyTable(); // or = MyTable.CreateMyTable(...);
  mydc.AddToMyTable(myRow);
  mydc.SaveChanges();
}    

對於其他代碼片段,我將跳過使用(...)部分和SubmitChanges / SaveChanges,因為每次都是一樣的。
將更改的對象附加到L2S中的datacontext / model (使用時間戳):

mydc.MyTable.Attach(myRow);

在L2E:

// you can use either
mydc.Attach(myRow);
// or (have not tested this)
mydc.AttachTo("MyTable", myRow);

將更改的對象附加到L2S中的datacontext / model(使用原始對象)

mydc.MyTable.Attach(myRow, myOriginalRow);

在L2E中( MSDN - 將更改應用到分離的對象 ):

mydc.Attach(myOriginalRow);
mydc.ApplyPropertyChanges(myOriginalRow.EntityKey.EntitySetName, myRow);

刪除L2S中的記錄

mydc.MyTable.DeleteOnSubmit(myRow);

在L2E:

mydc.DeleteObject(myRow);

在L2S中顯示創建的用於調試的SQL命令

mydc.Log = Console.Out;
// before mydc.SubmitChanges();

L2E中,您可以顯示查詢的SQL (感謝TFD):

using System.Data.Objects;
...
var sqlQuery = query as ObjectQuery;
var sqlTrace = sqlQuery.ToTraceString();

可悲的是,我發現沒有辦法輸出生成的調用SaveChanges() 的SQL - 你需要使用SQL分析器

如果不存在,則從方案創建數據庫L2S

if (!mydc.DatabaseExists())
  mydc.CreateDatabase();

在L2E:

// according to TFD there are no DDL commands in L2E

在L2S中對數據庫執行SQL命令

mydc.ExecuteCommand("ALTER TABLE dbo.MyTable ADD CONSTRAINT DF_MyTable_ID DEFAULT (newid()) FOR MyTableID");

在L2E:

要在EF中執行針對數據庫的eSQL命令(請注意,eSQL不支持DDL或DML(更改,插入,更新,刪除)命令):

using System.Data.EntityClient;
...
EntityConnection conn = this.Connection as EntityConnection;
using (EntityCommand cmd = conn.CreateCommand())
{
  conn.Open();
  cmd.CommandText = @"Select t.MyValue From MyEntities.MyTable As t";
  var result = cmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);
  result.Read();
  var myValue = result.GetValue(0);
  ...
  conn.Close();
}

命令文本在實體SQL中,與T-SQL不是100%相同的。
(感謝TFD)

如果您需要在同一連接上使用DDL / DML命令,則可能需要自己創建數據庫連接,使用自製數據庫連接來連接EF,然後將此連接用於DML命令。 不漂亮,看看你自己:

MetadataWorkspace workspace = new MetadataWorkspace(new string[] { "res://*/" }, new Assembly[] { Assembly.GetExecutingAssembly() });
using (SqlConnection sqlConnection = new SqlConnection("Data Source=salsa;Initial Catalog=SamAlyza;Integrated Security=True"))
using (EntityConnection econ = new EntityConnection(workspace, sqlConnection))
using (AlyzaDataClassesDataContext adc = new AlyzaDataClassesDataContext(econ))
{
   // now you can use the SqlConnection like always
}

新創建的L2S-Class提供默認值覆蓋部分方法OnCreated:

partial void OnCreated()
{
  Name = "";
}

在L2E中,您可以為您的表類創建一個默認的構造函數:

partial class MyTable
{
  public MyTable()
  {
    Name = "";
  }
}

以下示例是關於兩個表之間的1:n關係的。 我在SQL中定義表格,所以你知道我在寫什麼:

CREATE TABLE dbo.[MyTable]
(
 [MyTableID] uniqueidentifier NOT NULL ROWGUIDCOL CONSTRAINT [PK_MyTable] PRIMARY KEY,
 [Name] nvarchar(100) NOT NULL,
)  ON [PRIMARY]

ALTER TABLE dbo.[MyTable] ADD CONSTRAINT [DF_MyTable_ID] DEFAULT (newid()) FOR [MyTableID]


CREATE TABLE dbo.[MySubTable]
(
 [MySubTableID] uniqueidentifier NOT NULL ROWGUIDCOL CONSTRAINT [PK_MySubTable] PRIMARY KEY,
 [MyTableID] uniqueidentifier NULL,
 [Subname] decimal(18,2) NOT NULL,
)  ON [PRIMARY]

ALTER TABLE dbo.[MySubTable] ADD CONSTRAINT [DF_MySubTable_ID] DEFAULT (newid()) FOR [MySubTableID]

ALTER TABLE dbo.[MySubTable] ADD CONSTRAINT [FK_MySubTable_MyTable] FOREIGN KEY
(
 [MyTableID]
) REFERENCES dbo.[MyTable]
(
 [MyTableID]
) ON DELETE CASCADE

在L2S中使用相應的MySubTable記錄插入到MyTable中

  MyTable myRow = new MyTable();
  myRow.MySubTable.Add(new MySubTable());
  mydc.MyTable.InsertOnSubmit(myRow);

L2E非常相似:

  MyTable myRow = new MyTable();
  myRow.MySubTable.Add(new MySubTable());
  mydc.AddToSaLyWebsites(test);

在L2S 中搜索一個子表 ,你可以使用:

from u in adc.MySubTable 
where u.MyTableID == _searchForTableID && u.Name == _searchForName 
select u

在L2E中,您無法訪問關係列:

from u in adc.MySubTable 
where u.MyTable.MyTableID == _searchForTableID && u.Name == _searchForName 
select u

(當然你也可以使用)

from u in _searchForTable.MySubTable
where u.Name == _searchForName
select u

(奇怪的一面注意:_searchForTable不需要被連接到EF這個工作。)

雜質說明:

在L2S中,我可以在LINQ中使用miscellanous函數。 如果我在L2E中使用自定義函數,我得到一個NotSupportedException。 所以,而不是

from t in mydc.MyTable 
where t.Date >= _searchForDate && t.Date <= _searchForDate.AddHours(2) 
select t;

在L2E中需要使用

DateTime endDate = _searchForDate.AddHours(2);
from t in mydc.MyTable 
where t.Date >= _searchForDate && t.Date <= endDate 
select t;

雖然L2S可以從數據庫讀取自動生成的值,例如L2E中的自動生成的ID,但這似乎只能使用sql類型標識。

(當我絆倒他們時,我會在這篇文章中收集更多的差異,或者當有人加上他們的答案時)

一些鏈接,也許有幫助:
- Transact-SQL和Entity-SQL的區別
- NET - ADO.NET實體框架和LINQ to Entities
- Mike Taulty關於LINQ to Entities斷開連接(針對L2E的測試版2)




在L2S中,你可以使用像函數調用這樣的存儲過程。 在EF中,SP必須返回一個實體。 如果您的SP僅返回完整實體的子集,則可能會導致問題




Links