静态类
using System;
using System.Data.SqlClient;
namespace Contoso
{
public static class UsersRepository
{
private static string ConnectionString = @"Data Source=(local); Database=Users;User Id=sa;Password=password;";
public static User Load(int userId)
{
User user = new User();
SqlConnection connection = new SqlConnection(ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM Users WHERE UserId = " + userId,
connection);
var reader = command.ExecuteReader();
while (reader.Read())
{
user.Name = reader["Name"].ToString();
user.DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString());
user.Country = reader["Country"].ToString();
}
connection.Close();
return user;
}
}
}
如何为静态类实现工作单元和存储库模式?
您可以利用这样一个事实,即每当有人在此处调用代码时,他们都会通过公共入口点进行调用。这意味着,当调用方第一次进入类(通过所述公共方法)时,您将创建一个工作单元,并仅在同一方法向调用方返回值(或简单地结束)时将其处理。
大致如下:
public static class MyClass
{
public static User LoadUser(int userId)
{
using (var uow = new UnitOfWork())
{
DoSomething(uow);
var user = uow.UserRepository.GetById(userId);
return user;
}
}
}
从本质上讲,每个公共方法都应该创建、使用和处理单个工作单元实例。这确保了两件事:
- 并发调用使用各自独立的工作单元
- 在输入方法完成后,任何工作单元都不会在内存中徘徊
当您开始使用异步编程时,这确实会变得更棘手,但我省略了这一考虑,因为您也从未提到过它。
我喜欢实现一个应用坚实原理和单元可测试应用的解决方案
当您处理依赖项注入时,它会变得稍微棘手一些。静态类没有可注入的构造函数(注意:它们有构造函数,但不允许使用构造函数参数)。
所以注入你的依赖将是…非典型的。我能想到的一个解决方案是显式地设置内核(我在这里使用NInject作为一个例子):
public static class MyClass
{
public static IKernel Kernel { get; set; }
public static User LoadUser(int userId)
{
using (var uow = Kernel.Get<IUnitOfWork>())
{
DoSomething(uow);
var user = uow.UserRepository.GetById(userId);
return user;
}
}
}
如何设置内核(通过显式设置或直接为其分配默认值)取决于您。
如果没有NInject或任何类似的库,您可以使用Func<IUnitOfWork>
作为工厂方法来实现依赖注入,以创建按需工作单元:
public static class MyClass
{
public static Func<IUnitOfWork> CreateUnitOfWork { get; set; }
public static User LoadUser(int userId)
{
using (var uow = CreateUnitOfWork())
{
DoSomething(uow);
var user = uow.UserRepository.GetById(userId);
return user;
}
}
}
同样,如何设置工厂方法的内容取决于您,例如:
MyClass.CreateUnitOfWork = () => new UnitOfWork();