首先,我没有使用ORM,也不允许使用ORM。我必须使用ADO.NET手动滚动我的存储库。
我有两个对象:
public class Firm
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual IEnumerable<User> Users { get; set; }
}
public class User
{
public Guid Id { get; set; }
public string Username { get; set; }
public Firm Firm { get; set; }
}
注意彼此的引用,公司有一个用户列表,每个用户只有一个公司。
现在我想设计我的存储库:
public interface IFirmRepository
{
IEnumerable<Firm> FindAll();
Firm FindById(Guid id);
}
public interface IUserRepository
{
IEnumerable<User> FindAll();
IEnumerable<User> FindByFirmId(Guid firmId);
User FindById(Guid id);
}
到目前为止,这么好。我想从我的UserRepository为每个用户加载公司。 FirmRepository知道如何从持久性创建一个公司,所以我不想把这些知识保存在FirmRepository中。
public class UserRepository : IUserRepository
{
private IFirmRepository _firmRepository;
public UserRepository(IFirmRepository firmRepository)
{
_firmRepository = firmRepository;
}
public User FindById(Guid id)
{
User user = null;
using (SqlConnection connection = new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = "select id, username, firm_id from users where u.id = @ID";
SqlParameter userIDParam = new SqlParameter("@ID", id);
command.Parameters.Add(userIDParam);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
user = CreateListOfUsersFrom(reader)[0];
}
}
}
return user;
}
private IList<User> CreateListOfUsersFrom(SqlDataReader dr)
{
IList<User> users = new List<User>();
while (dr.Read())
{
User user = new User();
user.Id = (Guid)dr["id"];
user.Username = (string)dr["username"];
//use the injected FirmRepository to create the Firm for each instance of a User being created
user.Firm = _firmRepository.FindById((Guid)dr["firm_id"]);
}
dr.Close();
return users;
}
}
现在当我通过UserRepository加载任何用户时,我可以要求FirmRepository为我建立用户公司。到目前为止,这里没什么太疯狂的。
现在问题。
我想从我的FirmRepository加载用户列表。 UserRepository知道如何从持久性创建用户,因此我想将这些知识保存在UserRepository中。因此,我将对IUserRepository的引用传递给FirmRepository:
public class FirmRepository : IFirmRepository
{
private IUserRepository
public FirmRepository(IUserRepository userRepository)
{
}
}
但现在我们遇到了问题。 FirmRepository依赖于IUserRepository的实例,而UserRepository现在依赖于IFirmRepository的实例。因此,如果没有另一个实例,就无法创建一个存储库。
如果我将IoC容器保留在这个等式之外(我应该,b / c单元测试不应该使用IoC容器),我就无法完成我想要做的事情。
没问题,我只是创建一个FirmProxy来懒惰加载来自Firm的Users集合!这是一个更好的主意,b / c我不想在获得公司或公司列表时一直加载所有用户。
public class FirmProxy : Firm
{
private IUserRepository _userRepository;
private bool _haveLoadedUsers = false;
private IEnumerable<User> _users = new List<User>();
public FirmProxy(IUserRepository userRepository)
: base()
{
_userRepository = userRepository;
}
public bool HaveLoadedUser()
{
return _haveLoadedUsers;
}
public override IEnumerable<User> Users
{
get
{
if (!HaveLoadedUser())
{
_users = _userRepository.FindByFirmId(base.Id);
_haveLoadedUsers = true;
}
return _users;
}
}
}
所以,现在我有一个很好的代理对象来促进延迟加载。因此,当我从持久性创建FirmRepository中的公司时,我会返回一个FirmProxy。
public class FirmRepository : IFirmRepository
{
public Firm FindById(Guid id)
{
Firm firm = null;
using (SqlConnection connection = new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = "select id, name from firm where id = @ID";
SqlParameter firmIDParam = new SqlParameter("@ID", id);
command.Parameters.Add(firmIDParam);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
firm = CreateListOfFirmsFrom(reader)[0];
}
}
}
return firm;
}
private IList<Firm> CreateListOfFirmsFrom(SqlDataReader dr)
{
IList<FirmProxy> firms = new List<FirmProxy>([need an IUserRepository instance here!!!!]);
while (dr.Read())
{
}
dr.Close();
return firms;
}
但这仍然无效!!!
为了返回FirmProxy而不是Firm,我需要能够在FirmRepository类中新建一个FirmProxy。好吧,FirmProxy采用IUserRepository实例b / c,UserRepository包含如何从持久性创建User对象的知识。由于FirmProxy需要一个IUserRepository,我的FirmRepository现在也需要一个IUserRepository,我就回到原点!
所以,考虑到这个冗长的解释/解释/源代码,我怎样才能在没有以下情况下从UserRepository创建一个User实例和一个Firm实例:
我想到了NHiberante和Enitity Framework,看起来他们没有问题如何为我提供的一个简单例子生成sql。
有没有其他人有任何其他想法/方法/等等......这将有助于我在没有ORM的情况下实现我想做的事情?
或者可能有不同/更好的方法来解决这个问题?我不想失去的是能够从用户访问公司,或获取给定公司的用户列表
答案 0 :(得分:5)
您需要更清楚地考虑聚合根对象,即每个存储库的重点。您不为数据库中的每个表创建存储库,这不是目标。目的是识别您需要使用的聚合根对象,包括子表/记录,即用户(公司,地址,访问权限)。这就是您的存储库将返回到您的应用程序。
您遇到的困难是向您显示您的存储库结构不正确。任何时候我发现我的代码变得太难了,它会向我发出警告,我可能做错了,我过着自己的生活;)