将存储过程从 LINQ 迁移到 SQL 到 Entity Framework 6
Migrating stored procedure from LINQ to SQL to Entity Framework 6
我已经将我的项目从 Linq-to-SQL 迁移到 Entity Framework 6. 在解决了这么多问题之后,我终于遇到了一个我不知道该怎么办的问题。转换后,大约三分之一的单元测试失败,因为存储过程 returning 标量值 just work different way.
在 Linq-to-SQL 中,存储过程 return returned 值。在 EF 中,它们 return 受影响的行数。有一些变通方法需要更改存储过程(通常从 RETURN @retvalue
到 SELECT @retvalue
)。但这需要T-SQL的变化。该项目仍然包含一些 ASP.NET 过去的遗留代码,例如 aspnet_Membership_CreateUser
等等。这意味着我无法更改这些存储过程,因为 ASP.NET ADO.NET 成员资格提供程序部分使用了这些存储过程,部分 Linq-to-SQL 代码使用了这些存储过程。我考虑的解决方案是为这些遗留代码制作 T-SQL 包装器。
我想保持存储过程不变的另一个原因是,如果升级到 EF 不成功,可能会恢复到之前的提交。不想来回更改数据库。不过这个理由并没有那么强烈,只是我懒惰而已。
我知道会员提供程序是老式的,但我不能在一次提交中重写整个应用程序,我需要保持它的稳定性。
完成迁移的最佳方法是从 EF 调用存储过程,如 Linq-to-SQL,但我没有找到方法。 EF 在这方面让我很失望。经过多年的发展,EF 怎么可能不支持 returning 存储过程中的标量值?
你会如何解决这个问题?
嗨 Qub1n,
// Create the gender parameter var param1 = new SqlParameter {
ParameterName = "@userId",
Value = _userId };
// Create the return code var returnValue = new SqlParameter {
ParameterName = "@ReturnCode",
SqlDbType = System.Data.SqlDbType.Int,
Direction = System.Data.ParameterDirection.Output };
// Gender is an int column in the database.
_context
.Database
.ExecuteSqlCommand("exec @ReturnCode = GetGenderOfUser @userId",
param1, returnValue);
return (int)returnValue.Value;
这对我有用。我的存储过程是这样的:
CREATE PROCEDURE [dbo].[GetGenderOfUser]
-- Add the parameters for the stored procedure here
@userId uniqueidentifier
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @retval int
-- Insert statements for procedure here
set @retval = (select top(1) Gender from Users where Guid = @userId)
return @retval
END
如果可行,请告诉我!
最后我得到了包装器,它保留了数据库的原始功能(对于 ASP.NET MembershipProvider)并为 EntityFramework:
创建了存储过程的版本
CREATE PROCEDURE [dbo].[aspnet_UsersInRoles_AddUsersToRolesEF]
@ApplicationName nvarchar(256),
@UserNames nvarchar(4000),
@RoleNames nvarchar(4000),
@CurrentTimeUtc datetime
AS
BEGIN
DECLARE @return_value int
EXEC @return_value = [dbo].[aspnet_UsersInRoles_AddUsersToRoles]
@ApplicationName,
@UserNames,
@RoleNames,
@CurrentTimeUtc
SELECT @return_value
END
GO
现在我可以使用编译器检查存储过程中参数的数量和类型。
我已经将我的项目从 Linq-to-SQL 迁移到 Entity Framework 6. 在解决了这么多问题之后,我终于遇到了一个我不知道该怎么办的问题。转换后,大约三分之一的单元测试失败,因为存储过程 returning 标量值 just work different way.
在 Linq-to-SQL 中,存储过程 return returned 值。在 EF 中,它们 return 受影响的行数。有一些变通方法需要更改存储过程(通常从 RETURN @retvalue
到 SELECT @retvalue
)。但这需要T-SQL的变化。该项目仍然包含一些 ASP.NET 过去的遗留代码,例如 aspnet_Membership_CreateUser
等等。这意味着我无法更改这些存储过程,因为 ASP.NET ADO.NET 成员资格提供程序部分使用了这些存储过程,部分 Linq-to-SQL 代码使用了这些存储过程。我考虑的解决方案是为这些遗留代码制作 T-SQL 包装器。
我想保持存储过程不变的另一个原因是,如果升级到 EF 不成功,可能会恢复到之前的提交。不想来回更改数据库。不过这个理由并没有那么强烈,只是我懒惰而已。
我知道会员提供程序是老式的,但我不能在一次提交中重写整个应用程序,我需要保持它的稳定性。
完成迁移的最佳方法是从 EF 调用存储过程,如 Linq-to-SQL,但我没有找到方法。 EF 在这方面让我很失望。经过多年的发展,EF 怎么可能不支持 returning 存储过程中的标量值?
你会如何解决这个问题?
嗨 Qub1n,
// Create the gender parameter var param1 = new SqlParameter {
ParameterName = "@userId",
Value = _userId };
// Create the return code var returnValue = new SqlParameter {
ParameterName = "@ReturnCode",
SqlDbType = System.Data.SqlDbType.Int,
Direction = System.Data.ParameterDirection.Output };
// Gender is an int column in the database.
_context
.Database
.ExecuteSqlCommand("exec @ReturnCode = GetGenderOfUser @userId",
param1, returnValue);
return (int)returnValue.Value;
这对我有用。我的存储过程是这样的:
CREATE PROCEDURE [dbo].[GetGenderOfUser]
-- Add the parameters for the stored procedure here
@userId uniqueidentifier
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @retval int
-- Insert statements for procedure here
set @retval = (select top(1) Gender from Users where Guid = @userId)
return @retval
END
如果可行,请告诉我!
最后我得到了包装器,它保留了数据库的原始功能(对于 ASP.NET MembershipProvider)并为 EntityFramework:
创建了存储过程的版本CREATE PROCEDURE [dbo].[aspnet_UsersInRoles_AddUsersToRolesEF]
@ApplicationName nvarchar(256),
@UserNames nvarchar(4000),
@RoleNames nvarchar(4000),
@CurrentTimeUtc datetime
AS
BEGIN
DECLARE @return_value int
EXEC @return_value = [dbo].[aspnet_UsersInRoles_AddUsersToRoles]
@ApplicationName,
@UserNames,
@RoleNames,
@CurrentTimeUtc
SELECT @return_value
END
GO
现在我可以使用编译器检查存储过程中参数的数量和类型。