65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET Boilerplate 中使用存储过程、用户自定义函数和视图的自定义仓库

starIconstarIconstarIconstarIconstarIcon

5.00/5 (10投票s)

2017年8月3日

CPOL

2分钟阅读

viewsIcon

37995

如何在 ASP.NET Boilerplate 中创建自定义仓库,并在仓库中使用存储过程、视图和用户自定义函数

目录

Github 仓库 获取源码。

引言

在本文中,我将解释如何在 ASP.NET Boilerplate 中创建自定义仓库,并使用存储过程、视图和用户自定义函数。要了解更多关于 ASP.NET Boilerplate 框架的信息,请查看其 文档

要开始使用 ASP.NET Boilerplate 框架,您可以从 这里 下载一个启动模板。我选择了 ASP.NET Core 和多页 Web 应用程序,项目名称为 Acme.PhoneBook。如果您需要帮助设置模板,请参阅 此链接

在 Visual Studio 2017 中打开下载的解决方案后,我们看到如下解决方案结构

Projects

创建自定义仓库

我们将创建一个自定义仓库,使用存储过程、视图和用户自定义函数对 User 实体执行一些基本操作。要实现自定义仓库,只需从您的应用程序特定基础仓库类派生即可。

在领域层 (Acme.PhoneBook.Core) 中实现 interface

    public interface IUserRepository:  IRepository<User, long> 
    {
      ...
      ...
    }

在基础设施层 (Acme.PhoneBook.EntityFrameworkCore) 中实现仓库。

    public class UserRepository : PhoneBookRepositoryBase<User, long>, IUserRepository 
    {
        private readonly IActiveTransactionProvider _transactionProvider;

        public UserRepository(IDbContextProvider<PhoneBookDbContext> dbContextProvider, 
                              IActiveTransactionProvider transactionProvider)
            : base(dbContextProvider)
        {
            _transactionProvider = transactionProvider;
        }
        
        ...
        ...
    }  

辅助方法 (Helper Methods)

首先,我们创建一些将在其他方法之间共享的辅助方法,以执行一些通用任务

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<List<string>> GetUserNames()
{
    EnsureConnectionOpen();

    using (var command = CreateCommand("GetUsernames", CommandType.storedProcedure))
    {
        using (var dataReader = await command.ExecuteReaderAsync())
        {
            var result = new List<string>();

            while (dataReader.Read())
            {
                result.Add(dataReader["UserName"].ToString());
            }

            return result;
        }
    }
}

并在 IUserRepository 中定义 GetUserNames 方法

public interface IUserRepository:  IRepository<User, long> 
{
  ...
  Task<List<string>> 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<User, UserDto, 
long, PagedResultRequestDto, CreateUserDto, UserDto>, IUserAppService
{
    private readonly IUserRepository _userRepository;
	
    public UserAppService(..., IUserRepository userRepository)
        : base(repository)
    {
        ...
        _userRepository = userRepository;
    }
    
    ...
    
     public async Task<List<string>> 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)
);
}

用于 update 方法调用的存储过程

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<List<string>> GetAdminUsernames()
{
    EnsureConnectionOpen();
    using (var command = CreateCommand("SELECT * FROM dbo.UserAdminView", CommandType.Text))
    {
        using (var dataReader = await command.ExecuteReaderAsync())
        {
            var result = new List<string>();
            while (dataReader.Read())
            {
                result.Add(dataReader["UserName"].ToString());
            }
            return result;
        }
    }
} 

此方法的视图

SELECT        *
FROM            dbo.AbpUsers
WHERE        (Name = 'admin')

用户自定义函数

您可以像这样调用用户自定义函数

public async Task<GetUserByIdOutput> 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

Github 上的源码

源码已发布在 github 这里

© . All rights reserved.