在本文中,将探讨如何在ASP.NET Boilerplate框架中创建自定义存储库,并利用存储过程、视图和用户定义函数来执行数据库操作。ASP.NET Boilerplate是一个模块化的、多租户的、可扩展的框架,用于构建基于ASP.NET Core的应用程序。为了更深入地了解这个框架,建议参考其官方文档。
要开始使用ASP.NET Boilerplate框架,可以从下载一个启动模板。本文以ASP.NET Core和多页面Web应用程序为例,项目名为Acme.PhoneBook。如果需要帮助来设置模板,可以查看。
将创建一个自定义存储库,以便使用存储过程、视图和用户定义函数对用户实体执行一些基本操作。要实现自定义存储库,只需从应用程序特定的基存储库类派生。
在领域层(Acme.PhoneBook.Core)中实现接口。
public interface IUserRepository : IRepository
{
// ...
}
在基础设施层(Acme.PhoneBook.EntityFrameworkCore)中实现存储库。
public class UserRepository : PhoneBookRepositoryBase, IUserRepository
{
private readonly IActiveTransactionProvider _transactionProvider;
public UserRepository(IDbContextProvider dbContextProvider,
IActiveTransactionProvider transactionProvider)
: base(dbContextProvider)
{
_transactionProvider = transactionProvider;
}
// ...
}
首先,创建一些辅助方法,这些方法将由其他方法共享,以执行一些常见的任务:
private DbCommand CreateCommand(string commandText, CommandType commandType, params SqlParameter[] parameters)
{
var command = Context.Database.GetDbConnection().CreateCommand();
command.CommandText = commandText;
command.CommandType = commandType;
command.Transaction = GetActiveTransaction();
foreach (var parameter in parameters)
{
command.Parameters.Add(parameter);
}
return command;
}
private void EnsureConnectionOpen()
{
var connection = Context.Database.GetDbConnection();
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
private DbTransaction GetActiveTransaction()
{
return (DbTransaction)_transactionProvider.GetActiveTransaction(
new ActiveTransactionProviderArgs
{
{ "ContextType", typeof(PhoneBookDbContext) },
{ "MultiTenancySide", MultiTenancySide }
});
}
下面是一个存储过程调用示例,用于获取所有用户的用户名。将此添加到存储库实现中(UserRepository)。
public async Task> GetUserNames()
{
EnsureConnectionOpen();
using (var command = CreateCommand("GetUsernames", CommandType.StoredProcedure))
{
using (var dataReader = await command.ExecuteReaderAsync())
{
var result = new List();
while (dataReader.Read())
{
result.Add(dataReader["UserName"].ToString());
}
return result;
}
}
}
在IUserRepository中定义GetUserNames方法:
public interface IUserRepository : IRepository
{
// ...
Task> GetUserNames();
// ...
}
下面是被调用的存储过程:
USE [PhoneBookDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetUsernames]
AS
BEGIN
SET NOCOUNT ON;
SELECT UserName FROM AbpUsers
END
GO
现在已经实现了从数据库调用存储过程的函数。让在应用程序服务中使用它:
public class UserAppService : AsyncCrudAppService, IUserAppService
{
private readonly IUserRepository _userRepository;
public UserAppService(..., IUserRepository userRepository)
: base(repository)
{
...
_userRepository = userRepository;
}
...
public async Task> GetUserNames()
{
return await _userRepository.GetUserNames();
}
}
下面是另一个示例,它向存储过程发送一个参数以删除用户:
public async Task DeleteUser(EntityDto input)
{
await Context.Database.ExecuteSqlCommandAsync(
"EXEC DeleteUserById @id",
default(CancellationToken),
new SqlParameter("id", input.Id));
}
被调用的删除用户的存储过程:
USE [PhoneBookDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[DeleteUserById]
@id int
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM AbpUsers WHERE [Id] = @id
END
GO
另一个示例是发送一个参数来更新用户的电子邮件地址:
public async Task UpdateEmail(UpdateEmailDto input)
{
await Context.Database.ExecuteSqlCommandAsync(
"EXEC UpdateEmailById @email, @id",
default(CancellationToken),
new SqlParameter("id", input.Id),
new SqlParameter("email", input.EmailAddress));
}
被调用的更新方法的存储过程:
USE [PhoneBookDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[UpdateEmailById]
@email nvarchar(256),
@id int
AS
BEGIN
SET NOCOUNT ON;
UPDATE AbpUsers SET [EmailAddress] = @email WHERE [Id] = @id
END
GO
可以这样调用一个视图:
public async Task> GetAdminUsernames()
{
EnsureConnectionOpen();
using (var command = CreateCommand("SELECT * FROM dbo.UserAdminView", CommandType.Text))
{
using (var dataReader = await command.ExecuteReaderAsync())
{
var result = new List();
while (dataReader.Read())
{
result.Add(dataReader["UserName"].ToString());
}
return result;
}
}
}
此方法的视图:
SELECT * FROM dbo.AbpUsers WHERE (Name = 'admin')
可以这样调用用户定义函数:
public async Task GetUserById(EntityDto input)
{
EnsureConnectionOpen();
using (var command = CreateCommand("SELECT dbo.GetUsernameById(@id)", CommandType.Text,
new SqlParameter("@id", input.Id)))
{
var username = (await command.ExecuteScalarAsync()).ToString();
return new GetUserByIdOutput() { Username = username };
}
}
USE [PhoneBookDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[GetUsernameById]
@id int
RETURNS nvarchar(32)
AS
BEGIN
DECLARE @username nvarchar(32)
SELECT @username = [UserName] FROM AbpUsers WHERE [ID] = @id
RETURN @username
END
GO