Để bắt đầu, không, tôi không sử dụng ORM, cũng không được phép. Tôi phải cuộn các kho lưu trữ của mình bằng ADO.NET.Làm thế nào để phá vỡ phụ thuộc vòng tròn giữa các kho
Tôi có hai đối tượng:
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; }
}
lưu ý các tài liệu tham khảo với nhau, một Công ty có một danh sách người dùng, mỗi tài khoản chỉ có một Công ty.
Bây giờ tôi muốn thiết kế kho của tôi:
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);
}
Cho đến nay, như vậy tốt. Tôi muốn tải Công ty cho từng Người dùng từ UserRepository của tôi. FirmRepository biết cách tạo một Công ty từ sự kiên trì, vì vậy tôi muốn ot giữ kiến thức đó với 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;
}
}
bây giờ khi tôi tải bất kỳ Người dùng nào qua UserRepository, tôi có thể yêu cầu FirmRepository xây dựng Công ty của người dùng cho tôi. Cho đến nay, không có gì quá điên rồ ở đây.
Bây giờ là vấn đề.
Tôi muốn tải danh sách Người dùng từ FirmRepository của mình. UserRepository biết cách tạo User từ persistence, vì vậy tôi muốn giữ kiến thức đó với UserRepository. Vì vậy, tôi chuyển một tham chiếu đến IUserRepository tới FirmRepository:
public class FirmRepository : IFirmRepository
{
private IUserRepository
public FirmRepository(IUserRepository userRepository)
{
}
}
Nhưng bây giờ chúng ta có vấn đề. FirmRepository phụ thuộc vào một cá thể của IUserRepository, và UserRepository bây giờ phụ thuộc vào một cá thể của IFirmRepository. Vì vậy, một kho lưu trữ không thể được tạo ra mà không có một thể hiện của người khác.
Nếu tôi giữ hộp chứa IoC OUT phương trình này (và tôi nên, b/c Bài kiểm tra đơn vị không nên sử dụng các thùng chứa IoC), không có cách nào để tôi hoàn thành những gì tôi đang cố gắng làm.
Không có vấn đề, tuy nhiên, tôi sẽ chỉ tạo FirmProxy để tải bộ sưu tập Người dùng khỏi Công ty một cách lười biếng! Đó là một ý tưởng tốt hơn, b/c Tôi không muốn tải TẤT CẢ những người sử dụng tất cả thời gian khi tôi đi để có được một công ty hoặc một danh sách các công ty.
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;
}
}
}
Vì vậy, bây giờ tôi có một đối tượng proxy tốt để tạo điều kiện tải lười. Vì vậy, khi tôi đi để tạo ra một công ty trong FirmRepository từ kiên trì, tôi thay vì trả lại một 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;
}
Nhưng điều này vẫn không hoạt động !!!
Để trả lại FirmProxy thay vì Công ty, tôi cần có khả năng tạo FirmProxy mới trong lớp FirmRepository của mình. Vâng, FirmProxy lấy một cá thể IUserRepository b/c UserRepository chứa các kiến thức về cách tạo một đối tượng User từ persistence. Do FirmProxy cần một IUserRepository, FirmRepository của tôi bây giờ cũng cần một IUserRepository, và tôi quay trở lại hình vuông!
Vì vậy, với mã dài hơi-giải thích/nguồn này, làm thế nào tôi có thể đi về việc có thể để tạo ra một thể hiện của một người dùng từ FirmRepository và một thể hiện của Công ty từ UserRepository không:
- đặt mã tạo User trong FirmRepository. Tôi không thích điều này.Tại sao FirmRepository nên biết bất cứ điều gì về việc tạo ra một cá thể của một người dùng? Điều này với tôi là một sự vi phạm của SoC.
- Không sử dụng mẫu Bộ định vị dịch vụ. Nếu tôi đi tuyến đường này, tôi cảm thấy điều này rất khó kiểm tra. Bên cạnh đó, các nhà xây dựng của các đối tượng có sự phụ thuộc rõ ràng làm cho những phụ thuộc đó rõ ràng.
- tiêm tài sản thay vì tiêm xây dựng. Điều này không khắc phục được vấn đề gì, tôi vẫn cần một cá thể của IUserRepository khi khởi tạo FirmProxy bất kể sự phụ thuộc được tiêm vào FirmProxy như thế nào.
- Phải "ngừng hoạt động" đối tượng Công ty hoặc Người dùng và hiển thị FirmID trên Người dùng, ví dụ thay vì Công ty. Nếu tôi chỉ làm id, thì yêu cầu tải Công ty từ UserRepository sẽ biến mất, nhưng với sự phong phú của việc có thể yêu cầu đối tượng Công ty cho bất kỳ thứ gì với bối cảnh của một cá thể Người dùng cụ thể.
- Đặt chỗ đến ORM. Một lần nữa, tôi muốn làm điều đó, nhưng tôi không thể. Không có ORM. Đó là quy tắc (và có, đó là quy tắc crappy)
- giữ tất cả các phụ thuộc có thể tiêm của tôi khi phụ thuộc được tiêm từ cấp thấp nhất của ứng dụng, đó là giao diện người dùng (trong trường hợp của tôi, dự án web .NET). Không gian lận và sử dụng mã IoC trong FirmProxy để làm mới sự phụ thuộc thích hợp cho tôi. Đó là cơ bản bằng cách sử dụng mô hình Service Locator dù sao đi nữa.
Tôi nghĩ về NHiberante và Enitity Framework, và có vẻ như họ không có vấn đề gì về cách tạo sql cho một ví dụ đơn giản mà tôi đã trình bày.
Có ai khác có bất kỳ ý tưởng/phương pháp/etc nào khác ... sẽ giúp tôi đạt được những gì tôi muốn làm mà không có ORM không?
Hoặc có thể có một cách khác tốt hơn để tiếp cận điều này? Tôi không muốn mất là khả năng truy cập Công ty từ Người dùng hoặc để có danh sách Người dùng cho một Công ty cụ thể
Bình chọn để di chuyển đến http://programmers.stackexchange.com/ – MattDavey
@ indiecodemonkey Bạn đã tìm thấy một giải pháp? –