我想为想要从 linq2sql 迁移到 linq2entities 和 ADO.net 实体框架(此处称为 L2E)的人提供参考。我不想讨论这两个哪个更好。我只想为想要从一个过渡到另一个的人创建一个这两者之间的差异列表。
基本的东西很简单:删除 linq2sql 数据类,添加 ado.net 模型(从数据库创建)。将“实体”重命名为前数据上下文的名称。
现在,差异。例如,要在 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();
}
对于其他代码片段,我将跳过 using (...) 部分和 SubmitChanges/SaveChanges,因为它每次都是相同的。
将更改的对象附加到 L2S 中的数据上下文/模型(使用时间戳):
mydc.MyTable.Attach(myRow);
在 L2E 中:
// you can use either
mydc.Attach(myRow);
// or (have not tested this)
mydc.AttachTo("MyTable", myRow);
将更改的对象附加到 L2S 中的数据上下文/模型(使用原始对象):
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();
}
命令文本在 Entity SQL 中,与 T-SQL 不是 100% 相同。
(感谢 TFD)
如果您在同一连接上需要 DDL/DML 命令,您可能需要自己创建数据库连接,使用您自制的 db 连接连接 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中搜索 subtable,您可以使用:
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 中使用其他函数。如果我在 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 可以从数据库中读取自动生成的值,例如自动生成的 ID,但在 L2E 中,这似乎只能使用 sql 类型标识。
(当我偶然发现它们或有人在答案中添加它们时,我将在这篇文章中收集更多差异)
一些链接,可能有帮助:
- Transact-SQL 和 Entity-SQL 之间的区别
- NET - ADO.NET Entity Framework 和 LINQ to Entities
- Mike Taulty 关于 Disconnected LINQ to Entities(适用于 L2E 的 beta 2)