c# - कैसे रिपॉजिटरी के बीच परिपत्र निर्भरता को तोड़ने के लिए



.net dependency-injection (1)

के साथ शुरू करने के लिए, नहीं मैं एक ORM का उपयोग नहीं कर रहा हूँ, और न ही मैं करने की अनुमति दी है मुझे एडीओ। नेट का इस्तेमाल करते हुए अपने रिपॉजिटरी को हाथ से रोल करना होगा

मेरे पास दो ऑब्जेक्ट हैं:

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 से प्रत्येक उपयोगकर्ता के लिए फर्म लोड करना चाहता हूं। फर्म रीपोजिटरी जानता है कि कैसे दृढ़ता से एक फर्म बनाने के लिए, इसलिए मुझे लगता है कि ज्ञान उस फर्म रीपोजिटरी के साथ रखें

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 के माध्यम से किसी भी उपयोगकर्ता को लोड करने के लिए जाता हूं, तो मैं फर्म रीपोजिटरी से मेरे लिए उपयोगकर्ता की फर्म बनाने के लिए कह सकता हूँ अभी तक, यहां तक ​​कि कुछ भी पागल नहीं है

अब समस्या

मैं अपने फर्म रीपोजिटरी से उपयोगकर्ता की एक सूची को लोड करना चाहता हूं। UserRepository जानता है कि उपयोगकर्ता कैसे दृढ़ता से बना है, इसलिए मैं उस ज्ञान को UserRepository के साथ रखना चाहता हूं। इसलिए, मैं आईयूएसआरआर रिपोजिटरी के संदर्भ में फर्म रीपोजिटरी को पास करता हूं:

public class FirmRepository : IFirmRepository
{
    private IUserRepository
    public FirmRepository(IUserRepository userRepository)
    {

    }
}

लेकिन अब हमें एक समस्या है फर्म रिपोजिटरी IUserRepository के एक उदाहरण पर निर्भर करता है, और UserRepository अब IFirmRepository के एक उदाहरण पर निर्भर करता है। तो एक रिपॉजिटरी दूसरे के एक उदाहरण के बिना नहीं बनाया जा सकता है

अगर मैं आईओसी कंटेनरों को इस समीकरण से बाहर रखता हूं (और मुझे चाहिए, बी / सी यूनिट टेस्ट को आईओसी कंटेनरों का उपयोग नहीं करना चाहिए), मेरे लिए जो मैं करने की कोशिश कर रहा हूं पूरा करने का कोई रास्ता नहीं है।

कोई समस्या नहीं है, हालांकि, मैं फर्म से उपयोगकर्ता संग्रह आलसी लोड करने के लिए सिर्फ एक FirmProxy बनाऊँगा! यह एक बेहतर विचार है, बी / सी मैं सभी उपयोगकर्ताओं को हर समय लोड नहीं करना चाहता हूँ जब मैं फर्म या फर्म की एक सूची प्राप्त करने के लिए जाता हूं।

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;
        }
    }

}

इसलिए, आलसी लोडिंग की सुविधा के लिए अब मेरे पास एक अच्छा प्रॉक्सी ऑब्जेक्ट है I इसलिए, जब मैं दृढ़ता से फर्म रीपोजिटरी में एक फर्म बनाने के लिए जाता हूं, तो मैं इसके बजाय एक फर्म प्रोक्सिसी वापस लौटाता हूं

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;
}

लेकिन यह अभी भी काम नहीं कर रहा है !!!

एक फर्म की जगह एक फर्म प्रोसीसी वापस करने के लिए, मुझे अपने फर्म रीपोज़ोररी क्लास में एक फर्म प्रोसीसी को नया बनाने में सक्षम होना चाहिए। खैर, फर्म प्रोक्सी एक IUserRepository उदाहरण b / c लेता है UserRepository में एक उपयोगकर्ता ऑब्जेक्ट को कैसे दृढ़ता से बनाने का ज्ञान होता है। फर्मप्रॉक्सी के परिणामस्वरूप एक IUserRepository की आवश्यकता होती है, मेरे फर्म रीपोजिटरी को अब भी एक IUserRepository की आवश्यकता है, और मैं ठीक एक बार स्क्वायर एक में हूँ!

तो, यह लंबे समय से घुमावदार स्पष्टीकरण / स्रोत कोड दिया गया है, मैं उपयोगकर्ता रिपॉझिटरी से यूज़र रिपॉझिटरी से एक उपयोगकर्ता का एक उदाहरण और बिना उपयोगकर्ताRepository के फर्म का उदाहरण बनाने में कैसे सक्षम हो सकता हूं:

  1. फर्म रीपोज़ोररी में उपयोगकर्ता निर्माण कोड डालें मुझे यह पसंद नहीं है फ़र्म रिपोजिटरी को किसी उपयोगकर्ता का उदाहरण बनाने के बारे में कुछ क्यों पता होना चाहिए? यह मेरे लिए एसओसी का उल्लंघन है
  2. सर्विस लोकेटर पैटर्न का उपयोग नहीं करना अगर मैं इस मार्ग पर जाता हूं, तो मुझे लगता है कि यह परीक्षण करने के लिए बेहद कठिन है। इसके अलावा, वस्तुओं के निर्माणकर्ता जो स्पष्ट निर्भरताएं लेते हैं, उन निर्भरता को स्पष्ट करते हैं।
  3. कंस्ट्रक्टर इंजेक्शन के बजाय गुण इंजेक्शन यह किसी चीज़ को ठीक नहीं करता है, मुझे अभी भी एक आईयूआरआर रिपोजिटरी का एक उदाहरण होने की आवश्यकता है, जब कोई फर्म प्रोक्रॉसी को नया कर लेता है, चाहे कोई निर्भरता FirmProxy में इंजेक्शन क्यों न हो
  4. फर्म या उपयोगकर्ता ऑब्जेक्ट "खाली" करने के लिए और उपयोगकर्ता पर फर्मआईडी को बेनकाब करने के लिए, उदाहरण के लिए एक फर्म के बजाय अगर मैं सिर्फ आईडी बना रहा हूं, तो UserRepository से एक फर्म लोड करने की आवश्यकता दूर हो जाती है, लेकिन इसके साथ ही किसी दिए गए उपयोगकर्ता उदाहरण के संदर्भ को लेकर कुछ भी फर्म ऑब्जेक्ट से पूछने में सक्षम होने की समृद्धि होती है
  5. एक ORM को सहारा देना फिर, मैं यह करना चाहता हूं, लेकिन मैं नहीं कर सकता कोई ओआरएम नहीं है यही नियम है (और हाँ, यह गंदे नियम है)
  6. मेरे सभी इंजेक्शन-सक्षम निर्भरता को आवेदन के निम्नतम स्तर से इंजेक्शन के रूप में निर्भरता के रूप में रखें, जो कि यूआई है (मेरे मामले में, एक .NET वेब प्रोजेक्ट)। मेरे लिए उपयुक्त निर्भरता को नया करने के लिए फर्म प्रोक्सी में धोखाधड़ी और IoC कोड का उपयोग नहीं करना यह मूल रूप से सेवा लोकेटर पैटर्न का उपयोग किसी भी तरह से है

मैं NHiberante और Enitity फ्रेमवर्क के बारे में सोचता हूं, और ऐसा लगता है कि मैंने एक सरल उदाहरण के लिए एसक्यूएल कैसे उत्पन्न किया है, जिसे मैंने प्रस्तुत किया है यह जानने में कोई समस्या नहीं है

क्या किसी और के पास कोई अन्य विचार / विधियां / आदि हैं ... जो मुझे ओआरएम के बिना क्या करना चाहते हैं?

या हो सकता है कि इस दृष्टिकोण के लिए एक अलग / बेहतर तरीका है? चाहते हैं कि मैं हारना नहीं चाहता हूं एक उपयोगकर्ता से फर्म तक पहुंचने की क्षमता है, या किसी निश्चित फर्म के लिए उपयोगकर्ता की सूची प्राप्त करने की क्षमता है


आपको अपनी कुल रूट ऑब्जेक्ट्स के बारे में अधिक स्पष्ट रूप से सोचने की जरूरत है, अर्थात प्रत्येक रिपॉजिटरी का फ़ोकस। आप अपने डेटाबेस में प्रत्येक तालिका के लिए एक रिपॉजिटरी नहीं बनाते, जो उद्देश्य नहीं है इरादा कुल रूट ऑब्जेक्ट की पहचान करना है जिसके साथ काम करना जरूरी है, इसमें बच्चे के तालिकाओं / रिकॉर्ड शामिल हैं, अर्थात उपयोगकर्ता (फर्म, पता, ऐक्सेस राइट्स)। यही आपके रिपॉजिटरी आपके ऐप पर लौट आएगा।

आप जो कठिनाई कर रहे हैं वह आपको दिखा रहा है कि आपकी रिपॉजिटरी सही ढंग से संरचित नहीं हैं। कभी भी मुझे लगता है कि मेरा कोड बहुत मुश्किल हो रहा है, यह मेरे साथ चेतावनी उठाता है कि मैं शायद यह गलत कर रहा हूं, मैं अपनी जिंदगी जीता हूं;)





circular-dependency