Note that there are some explanatory texts on larger screens.

plurals
  1. POCircular reference between Assemblies in C# and Visual Studio 2005
    text
    copied!<p>I am working hard to standardize one single way of Layered/n-Tiered design of my all applications.</p> <p>I am trying to make all my applications 5 tiered.</p> <p>Code:</p> <hr> <h2>| UI |</h2> <h2> |</h2> <h2>| Business Object |</h2> <h2> |</h2> <h2>| OR-Mapper |</h2> <h2> |</h2> <h2>| Data Access |</h2> <h2> |</h2> <h2>| RDBMS |</h2> <p>Suppose I am developing an application with a log-in/log-out capability for users. I am creating 4 projects under a VS2005 solution. Each project is for one of the upper 4 layers. I am designing my Business Object class as follows:-</p> <pre><code>public class User { private string _username; public string Username { get { return _username; } set { _username = value; } } private string _password; public string Password { get { return _password; } set { _password = value; } } public User() { } public bool LogIn(String username, String password) { bool success = false; if (UserMapper.UsernameExists(username)) { success = UserMapper.UsernamePasswordExists(username, password); } else { //do nothing } return success; } public bool LogOut() { bool success; //----some logic return success; } public static User GetUserByUsername(string username) { return UserMapper.GetUserByUsername(username); } public static UserCollection GetByUserTypeCode(string code) { return UserMapper.GetByUserTypeCode(code); } } </code></pre> <p>This is how I am giving my objects some functionality that matches the real-world scenario. Here GetByUsername() and GetByUserTypeCode() are getter functions. These functions does't match a real-world logic. Coz, in real-world, a User never "Gets by Username" or "Gets by UserTypeCode". So these functions are kept static.</p> <p>My class for O-R Mapper layer is as follows:-</p> <pre><code>public static class UserMapper { public static bool UsernameExists(String username) { bool exists = false; if (UserDA.CountUsername(username) == 1) { exists = true; } return exists; } public static bool UsernamePasswordExists(String username, String password) { bool exists = false; if (UserDA.CountUsernameAndPassword(username, password) == 1) { exists = true; } return exists; } } </code></pre> <p>And finally, the DA class is as follows:-</p> <pre><code>public static class UserDA { public static int CountUsername(string username) { int count = -1; SqlConnection conn = DBConn.Connection; if (conn != null) { try { SqlCommand command = new SqlCommand(); command.Connection = conn; command.CommandText = @"SELECT COUNT(*) FROM User WHERE User_name = @User_name"; command.Parameters.AddWithValue("@User_name", username); command.Connection.Open(); object idRaw = command.ExecuteScalar(); command.Connection.Close(); if (idRaw == DBNull.Value) { count = 0; } else { count = (int)idRaw; } } catch (Exception ex) { count = -1; } } return count; } public static int CountUsernameAndPassword(string username, string password) { int count = 0; SqlConnection conn = DBConn.Connection; if (conn != null) { try { SqlCommand command = new SqlCommand(); command.Connection = conn; command.CommandText = @"SELECT COUNT(*) FROM User WHERE User_name = @User_name AND Pass_word = @Pass_word"; command.Parameters.AddWithValue("@User_name", username); command.Parameters.AddWithValue("@Pass_word", password); command.Connection.Open(); object idRaw = command.ExecuteScalar(); command.Connection.Close(); if (idRaw == DBNull.Value) { count = 0; } else { count = (int)idRaw; } } catch (Exception ex) { count = 0; } } return count; } public static int InsertUser(params object[] objects) { int count = -1; SqlConnection conn = DBConn.Connection; if (conn != null) { try { SqlCommand command = new SqlCommand(); command.Connection = conn; command.CommandText = @"INSERT INTO User(ID, User_name, Pass_word, RegDate, UserTypeCode, ActualCodeOrRoll) VALUES(@ID, @User_name, @Pass_word, @RegDate, @UserTypeCode, @ActualCodeOrRoll)"; command.Parameters.AddWithValue("@ID", objects[0]); command.Parameters.AddWithValue("@User_name", objects[1]); command.Parameters.AddWithValue("@Pass_word", objects[2]); command.Parameters.AddWithValue("@RegDate", objects[3]); command.Parameters.AddWithValue("@UserTypeCode", objects[4]); command.Parameters.AddWithValue("@ActualCodeOrRoll", objects[5]); command.Connection.Open(); count = command.ExecuteNonQuery(); command.Connection.Close(); } catch (Exception ex) { count = -1; } } return count; } public static SqlDataReader GetUserByUsername(string username) { SqlDataReader dataReader = null; SqlConnection conn = DBConn.Connection; if (conn != null) { try { SqlCommand command = new SqlCommand(); command.Connection = conn; command.CommandText = @"SELECT * FROM User WHERE User_name = @User_name"; command.Parameters.AddWithValue("@User_name", username); command.Connection.Open(); dataReader = command.ExecuteReader(CommandBehavior.CloseConnection); } catch (Exception ex) { dataReader.Close(); dataReader.Dispose(); } } return dataReader; } public static SqlDataReader GetUserByUserTypeCode(string userTypeCode) { SqlDataReader dataReader = null; SqlConnection conn = DBConn.Connection; if (conn != null) { try { SqlCommand command = new SqlCommand(); command.Connection = conn; command.CommandText = @"SELECT * FROM User WHERE UserTypeCode = @UserTypeCode"; command.Parameters.AddWithValue("@UserTypeCode", userTypeCode); command.Connection.Open(); dataReader = command.ExecuteReader(CommandBehavior.CloseConnection); } catch (Exception ex) { dataReader.Close(); dataReader.Dispose(); } } return dataReader; } } </code></pre> <p>If anyone closely examine the these classes he can understand that, O-R Mapper layer needs the reference of BusinessObject-layer. BusinessObject- layer also needs a reference of O-R Mapper-layer.</p> <p>This should create a circular dependency.</p> <p>How can I avoid this problem?</p> <p>Someone suggested using plain Data Transfer Objects (DTO). But, as far as I know, according to OOP, attributes and functionality of a real-world object should be grouped together as a class. If I use DTO then how can I encapsulate functionality into a class? Moreover I am creating another class without any attribute (BO). To me that is breach of OOP in both ways. If I do so, then what is OOP for in this world? The same answer can be applied for "UserManager" classes.</p> <p>I found a <a href="http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=476" rel="nofollow noreferrer">blog</a>. </p> <p>It discusses about implementing interfaces. Define a separate interface, implement it in your data class in the BusinessObject and program against your interface in the BusinessObject and in the OR-Mapper layer.</p> <p>But I could not do this.</p> <p>Can anyone show me that with a practical example?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload