I have the following seperation of logic in my application, as you can see I have a class called SimpleController which is what I use to Import and Find SimpleEntities.
I read all the SimpleEntities into memory List cause I search these Entities very often and its a lot faster then reading from the database everytime I want to search for an Entity.
Would it be better to move the logic where I read and store the SimpleEntities into memory into the SimpleLogic class instead of the SimpleController class?
public class SimpleEntity
{
public int SimpleId { get; set; }
public string SimpleName { get; set; }
}
public class SimpleDAL
{
public ICollection<SimpleEntity> GetAllSimpleEntities()
{
//Retrieve SimpleEntities from Database
}
public void InsertSimpleEntity(SimpleEntity simpleEntity)
{
//Insert simple Entity into Database
}
}
public class SimpleLogic
{
private readonly SimpleDAL simpleDAL = new SimpleDAL();
public ICollection<SimpleEntity> GetAllSimpleEntities()
{
return simpleDAL.GetAllSimpleEntities();
}
public void InsertSimpleEntity(SimpleEntity simpleEntity)
{
//Validate simpleEntity before adding to database
if (simpleEntity.SimpleId <= 0)
throw new Exception("Invalid SimpleEntity Id: " + simpleEntity.SimpleId);
if (String.IsNullOrEmpty(simpleEntity.SimpleName))
throw new Exception("SimpleEntity Name cannot be empty or null");
simpleDAL.InsertSimpleEntity(simpleEntity);
}
}
public class SimpleController
{
private readonly SimpleLogic simpleLogic = new SimpleLogic();
private List<SimpleEntity> simpleEntities;
public SimpleController()
{
simpleEntities = simpleLogic.GetAllSimpleEntities().ToList();
}
public int FindSimpleIndex(int simpleId)
{
return simpleEntities.FindIndex(p=> p.SimpleId == simpleId);
}
public void ImportOtherSimpleEntity(OtherSimpleEntity otherSimpleEntity)
{
if (otherSimpleEntity.Operation == "Update")
{
int index = FindSimpleIndex(otherSimpleEntity.OtherSimpleId);
//If entity was found update SimpleEntity
if (index > -1)
{
//Call SimpleLogic.UpdateSimpleEntity(Pass in SimpleEntity);
}
}
}
}
I'd perhaps implement a SimpleEntityManager which can be referenced from within the controller, and can operate outside it if necessary. So the controller handles the MVC aspects of the system, and the SimpleEntityManager manages the SimpleEntities.
As an aside, InsertSimpleEntity() appears to be performing validation on SimpleEntity fields. I would normally rather the SimpleEntity performs that validation itself (most likely during construction).
Related
I have a class named ValidationsResult with this properties:
public class ValidationsResult
{
public bool IsValid { get; set; }
public string[] Errors { get; set; }
public void AddError(string error)
{
Errors.Append(error);
}
}
But I want that the property IsValid to be read only, and depending if the object has Errors or not modify that property automatically.
How can I do that?
public class ValidationsResult
{
public bool IsValid { get => Errors != null && Errors.Length == 0; } // no errors = valid
public string[] Errors { get; set; }
public void AddError(string error)
{
Errors.Append(error);
}
}
That will make it readonly and it will tell you if you have errors
Based on the comment, yes. Better if you designed it in the following fashion.
public class ValidationsResult
{
public bool IsValid { get => Errors.Count == 0; } // or !Errors.Any()
public List<string> Errors { get; } = new List<string>();
public void AddError(string error)
{
Errors.Add(error);
}
}
You initialize the errors but outside consumer can still use it. Hence - next evolution
public class ValidationsResult
{
private List<string> _errors = new List<string>(); // private member
public bool IsValid { get => _errors.Count == 0; } // or !Errors.Any()
public string[] Errors { get => _errors.ToArray(); }
public void AddError(string error)
{
_errors.Add(error);
}
}
Now you encapsulating your error collection not letting consumer to modify it directly, but via AddError
As an answer is already posted and accepted, I just want to point to a different thing.
Never implement this type of mechanism in a class! Keep classes as simple as possible.
Please use classes as POCOs, and implement this type of logic in a different layer of the application (e.g. Business Logic layer).
Otherwise, over time, your application will become complex and convoluted and hence hard to maintain.
Is there some way of build a class from a external builder class without letting their setters public? I don't want to allow a invalid instance of a class to exist without the necessary validations.
The only way I found so far is creating a constructor with the required parameters and validations.
I made a example with few properties to be filled, but imagine a case with various.
public class Computer
{
public string Motherboard { get; private set; }
public string RamMemory { get; private set; }
public string Cpu { get; private set; }
public Computer(string motherboard, string ramMemory, string cpu)
{
ValidateMotherboard(motherboard);
ValidateRamMemory(ramMemory);
ValidateCpu(cpu);
Motherboard = motherboard;
RamMemory = ramMemory;
Cpu = cpu;
}
private void ValidateMotherboard(string motherboard)
{
if (motherboard == null)
throw new ArgumentNullException(nameof(motherboard));
}
private void ValidateRamMemory(string ramMemory)
{
if (ramMemory == null)
throw new ArgumentNullException(nameof(ramMemory));
}
private void ValidateCpu(string cpu)
{
if (cpu == null)
throw new ArgumentNullException(nameof(cpu));
else if (!cpu.ToLower().Contains("ryzen"))
throw new ArgumentException("Only AMD Ryzen CPU's is good enough.");
}
}
public class ComputerBuilder
{
private string _motherboard;
private string _ramMemory;
private string _cpu;
public ComputerBuilder SetMotherboard(string motherboard)
{
_motherboard = motherboard;
return this;
}
public ComputerBuilder SetRamMemory(string ramMemory)
{
_ramMemory = ramMemory;
return this;
}
public ComputerBuilder SetCpu(string cpu)
{
_cpu = cpu;
return this;
}
public Computer Build() => new Computer(_motherboard, _ramMemory, _cpu);
}
I just want to have builders that easies the construction of classes with too much parameters. Any ideias of how do this putting the validations on the builder without allow a invalid instance to exist?
I have class which have too many related calculated properties.
I have currently kept all properties are read only.
some properties need long calculation and it is called again when its related properties are needed.
How can create this complex object .Also i want these properties should not be set from external code. I need show hide as i am binding properties for UI. Also i think order is also important.
My Class is something like
public string A
{
get
{
return complexMethod();
;
}
}
public string B
{
get
{
if (A == "value")
return "A";
else return "B";
;
}
}
public bool ShowHideA
{
get
{
return string.IsNullOrEmpty(A);
;
}
}
public bool ShowHideB
{
get
{
return string.IsNullOrEmpty(B);
;
}
}
public string complexMethod()
{
string value = "";
// calculation goes here
return value;
}
}
Thanks
You need to use Lazy type provided by .net:
Lazy<YourType> lazy = new Lazy<YourType>();
Make your properties internal to not be set from external code.
Well tall order isn't it?
One of the coolest things about extension methods is you can use types. This is perfect for writing external programs to calculate property values. Start like this...
public static class XMLibrary
{
public static MC CalculateValues(this MC myclass)
{
//for each property calculate the values here
if (myclass.Name == string.Empty) myclass.Name = "You must supply a name";
if (myclass.Next == 0) myclass.Next = 1;
//when done return the type
return myclass;
}
}
public class MC
{
public string Name { get; set; }
public int Next { get; set; }
}
public class SomeMainClass
{
public SomeMainClass()
{
var mc = new MC { Name = "test", Next = 0 };
var results = mc.CalculateValues();
}
}
There are many other ways to do class validation on a model, for example dataannotations comes to mind, or IValidatableObject works too. Keeping the validation separate from the class is a good idea.
//Complex properites are simple
public class MyComplextClass{
public List<MyThings> MyThings {get;set;}
public List<FileInfo> MyFiles {get;set;}
public List<DateTime> MyDates {get;set;}
}
I have a class which has been steadily growing over time. It's called LayoutManager.
It started as a way for me to keep track of which dynamically created controls were on my page. So, for instance, I have this:
public CormantRadDockZone()
{
ID = String.Format("RadDockZone_{0}", Guid.NewGuid().ToString().Replace('-', 'a'));
MinHeight = Unit.Percentage(100);
BorderWidth = 0;
HighlightedCssClass = "zoneDropOk";
CssClass = "rightRoundedCorners";
LayoutManager.Instance.RegisteredDockZones.Add(this);
}
In this way, during the beginning stages of the Page Lifecycle, controls would be re-created and they would add themselves to their respective control's list.
A while later I found myself passing the 'Page' object between methods. This was for the sole purpose of being able to access controls found on Page. I thought to myself -- well, I already have a Layout Manager, I'll just treat the static controls in the same way.
As such, my Page_Init method now looks like this mess:
protected void Page_Init(object sender, EventArgs e)
{
SessionRepository.Instance.EnsureAuthorized();
LayoutManager.Instance.RegisteredPanes.Clear();
LayoutManager.Instance.RegisteredDocks.Clear();
LayoutManager.Instance.RegisteredDockZones.Clear();
LayoutManager.Instance.RegisteredSplitters.Clear();
LayoutManager.Instance.RegisteredSplitBars.Clear();
LayoutManager.Instance.RegisteredPageViews.Clear();
LayoutManager.Instance.CheckBox1 = CheckBox1;
LayoutManager.Instance.CheckBox4 = CheckBox4;
LayoutManager.Instance.StartEditButton = StartEditButton;
LayoutManager.Instance.FinishEditButton = FinishEditButton;
LayoutManager.Instance.RadNumericTextBox1 = RadNumericTextBox1;
LayoutManager.Instance.RadNumericTextBox2 = RadNumericTextBox2;
LayoutManager.Instance.LeftPane = LeftPane;
LayoutManager.Instance.DashboardUpdatePanel = DashboardUpdatePanel;
LayoutManager.Instance.CustomReportsContainer = CustomReportsContainer;
LayoutManager.Instance.HistoricalReportsContainer = HistoricalReportsContainer;
RegenerationManager.Instance.RegenerateReportMenu();
LayoutManager.Instance.MultiPage = DashboardMultiPage;
LayoutManager.Instance.MultiPageUpdatePanel = MultiPageUpdatePanel;
LayoutManager.Instance.TabStrip = DashboardTabStrip;
RegenerationManager.Instance.RegenerateTabs(DashboardTabStrip);
RegenerationManager.Instance.RegeneratePageViews();
LayoutManager.Instance.Timer = RefreshAndCycleTimer;
LayoutManager.Instance.Timer.TimerEvent += DashboardTabStrip.DoTimerCycleTick;
RegenerationManager.Instance.RegeneratePageState();
}
I'm looking at that and saying no, no, no. That is all wrong. Yet, there are controls on my page which are very dependent on each other, but do not have access to each other. This is what seems to make this so necessary.
I think a good example of this in practice would be using UpdatePanels. So, for instance, DashboardUpdatePanel is being given to the LayoutManager. There are controls on the page which, conditionally, should cause the entire contents of the dashboard to update.
Now, in my eyes, I believe I have two options:
Inside the object wanting to call UpdatePanel.Update(), I recurse up through parent objects, checking type and ID until I find the appropriate UpdatePanel.
I ask LayoutManager for the UpdatePanel.
Clearly the second one sounds cleaner in this scenario... but I find myself using that same logic in many instances. This has resulted in a manager class which looks like this:
public class LayoutManager
{
private static readonly ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly LayoutManager _instance = new LayoutManager();
private LayoutManager() { }
public static LayoutManager Instance
{
get { return _instance; }
}
private IList<CormantRadDock> _registeredDocks;
private IList<CormantRadDockZone> _registeredDockZones;
private IList<CormantRadPane> _registeredPanes;
private IList<CormantRadSplitter> _registeredSplitters;
private IList<CormantRadSplitBar> _registeredSplitBars;
private Dictionary<string, StyledUpdatePanel> _registeredUpdatePanels;
private IList<CormantRadPageView> _registeredPageViews;
public RadMultiPage MultiPage { get; set; }
public CormantTimer Timer { get; set; }
public CormantRadListBox HistoricalReportsContainer { get; set; }
public CormantRadListBox CustomReportsContainer { get; set; }
public StyledUpdatePanel MultiPageUpdatePanel { get; set; }
public CormantRadTabStrip TabStrip { get; set; }
public RadPane LeftPane { get; set; }
public StyledUpdatePanel DashboardUpdatePanel { get; set; }
public RadButton ToggleEditButton { get; set; }
public CheckBox CheckBox1 { get; set; }
public CheckBox CheckBox4 { get; set; }
public RadNumericTextBox RadNumericTextBox1 { get; set; }
public RadNumericTextBox RadNumericTextBox2 { get; set; }
public RadButton StartEditButton { get; set; }
public RadButton FinishEditButton { get; set; }
public IList<CormantRadDock> RegisteredDocks
{
get
{
if (Equals(_registeredDocks, null))
{
_registeredDocks = new List<CormantRadDock>();
}
return _registeredDocks;
}
}
public IList<CormantRadDockZone> RegisteredDockZones
{
get
{
if (Equals(_registeredDockZones, null))
{
_registeredDockZones = new List<CormantRadDockZone>();
}
return _registeredDockZones;
}
}
public IList<CormantRadPane> RegisteredPanes
{
get
{
if (Equals(_registeredPanes, null))
{
_registeredPanes = new List<CormantRadPane>();
}
return _registeredPanes;
}
}
public IList<CormantRadSplitter> RegisteredSplitters
{
get
{
if (Equals(_registeredSplitters, null))
{
_registeredSplitters = new List<CormantRadSplitter>();
}
return _registeredSplitters;
}
}
public IList<CormantRadSplitBar> RegisteredSplitBars
{
get
{
if (Equals(_registeredSplitBars, null))
{
_registeredSplitBars = new List<CormantRadSplitBar>();
}
return _registeredSplitBars;
}
}
public Dictionary<string, StyledUpdatePanel> RegisteredUpdatePanels
{
get
{
if( Equals( _registeredUpdatePanels, null))
{
_registeredUpdatePanels = new Dictionary<string, StyledUpdatePanel>();
}
return _registeredUpdatePanels;
}
}
public IList<CormantRadPageView> RegisteredPageViews
{
get
{
if (Equals(_registeredPageViews, null))
{
_registeredPageViews = new List<CormantRadPageView>();
}
return _registeredPageViews;
}
}
public StyledUpdatePanel GetBaseUpdatePanel()
{
string key = MultiPage.PageViews.Cast<CormantRadPageView>().Where(pageView => pageView.Selected).First().ID;
return RegisteredUpdatePanels[key];
}
public CormantRadDockZone GetDockZoneByID(string dockZoneID)
{
CormantRadDockZone dockZone = RegisteredDockZones.Where(registeredZone => dockZoneID.Contains(registeredZone.ID)).FirstOrDefault();
if (Equals(dockZone, null))
{
_logger.ErrorFormat("Did not find dockZone: {0}", dockZoneID);
}
else
{
_logger.DebugFormat("Found dockZone: {0}", dockZoneID);
}
return dockZone;
}
public CormantRadPane GetPaneByID(string paneID)
{
CormantRadPane pane = RegisteredPanes.Where(registeredZone => paneID.Contains(registeredZone.ID)).FirstOrDefault();
if (Equals(pane, null))
{
_logger.ErrorFormat("Did not find pane: {0}", paneID);
}
else
{
_logger.DebugFormat("Found pane: {0}", paneID);
}
return pane;
}
public CormantRadDock GetDockByID(string dockID)
{
CormantRadDock dock = RegisteredDocks.Where(registeredZone => dockID.Contains(registeredZone.ID)).FirstOrDefault();
if (Equals(dock, null))
{
_logger.ErrorFormat("Did not find dock: {0}", dockID);
}
else
{
_logger.DebugFormat("Found dock: {0}", dockID);
}
return dock;
}
}
Am I on a bad path? What steps are generally taken at this point?
EDIT1: I have decided to start down the path of improvement by finding the controls which are least-integrated into LayoutManager and finding ways of breaking them down into separate objects. So, for instance, instead of assigning the HistoricalReportsContainer and CustomReportsContainer objects to LayoutManager (which is then used in RegenerationManager.RegenerateReportMenu) I have moved the code to RadListBox "Load" event. There, I check the ID of the control which is loading and react accordingly. A strong first improvement, and has removed 2 controls and a method from LayoutManager!
Inversion of control is a general approach that people use for such problems. Your dependencies should not be stored in the one Jack-Bauer-kind-of-style class, but rather be injected, for example via constructor. Take a look at the IoC containers, such as Castle Windsor, Unity, NInject or any other.
I'm not sure how this would interact with future plans of MVC, but had you considered refactoring chunks of LayoutManager into an abstract class that inherits from Page, then having your actual pages inherit from that abstract class?
Is there any issues in using version 2,to get the same results as version 1.
Or is this just bad coding.
Any Ideas
public class Customer
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
int Age { get; set; }
}
public interface ICustomer
{
void AddNewCustomer(Customer Customer);
void AddNewCustomer(string EmailAddress, int Age);
void RemoveCustomer(Customer Customer);
}
public class BALCustomer
{
private readonly ICustomer dalCustomer;
public BALCustomer(ICustomer dalCustomer)
{
this.dalCustomer = dalCustomer;
}
public void Add_A_New_Customer(Customer Customer)
{
dalCustomer.AddNewCustomer(Customer);
}
public void Remove_A_Existing_Customer(Customer Customer)
{
dalCustomer.RemoveCustomer(Customer);
}
}
public class CustomerDataAccess : ICustomer
{
public void AddNewCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void AddNewCustomer(string EmailAddress, int Age)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void RemoveCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
}
// VERSION 2
public class Customer_New : DataRespository<CustomerDataAccess>
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class DataRespository<T>
where T:class,new()
{
private T item = new T();
public T Execute { get { return item; } set { item = value; } }
public void Update()
{
//TO BE CODED
}
public void Save()
{
//TO BE CODED
}
public void Remove()
{
//TO BE CODED
}
}
class Program
{
static void Main(string[] args)
{
Customer_New cus = new Customer_New()
{
Age = 10,
EmailAddress = "this#demo.com"
};
cus.Save();
cus.Execute.RemoveCustomer(new Customer());
// Repository Version
Customer customer = new Customer()
{
EmailAddress = "new#demo.com",
CustomerID = 10
};
BALCustomer bal = new BALCustomer(new CustomerDataAccess());
bal.Add_A_New_Customer(customer);
}
}
You have a lot of things going on that aren't making a lot of sense.
First of all, the names of properties should always be a noun (singular or plural) or a "being" verb like Is* or Has*. These are properties of an object, and should be similar to what you would say in response to a question like "Would you please describe your desk?" Execute is an operation, and should therefore be a method. Likewise, your naming conventions in Version 1 should be PascalCased which means no underscores and the first letter of all words should be capitalized. These aren't die-hard truths, but they are considered OOP common C# coding standards.
Secondly, the code in your main method isn't actually implementing anything in your generic class. The only thing your class is actually doing is creating an instance of CustomerDataAccess. The Save() method won't do anything, unless you specifically are able to call item.Save() In order to use your Save, Update, Delete functionality on your generic class, your CustomerDataAccess class will have to implement an interface expected by your generic class. For instance:
public interface IDataAccess<T> : where T : YourBaseObject {
public void Update(T item);
public void Save(T item);
public void Remove(T item);
}
public class Customer : YourBaseObject {
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class CustomerDataAccess :
DataRespository<IDataAccess<Customer>> {
public void PerformCustomerOnlyAction(Customer customer) {
/* do stuff */
}
}
Now, you can create a generic class that handles basic CRUD functionality, and all other functionality is accessible through the BaseRepository property.
/* e.g. T = IDataAccess<Customer>, K = Customer */
public class DataRespository<T>
where T : IDataAccess<K>, new()
where K : YourBaseObject, new()
{
private T _base;
public T BaseRepository {
get {
if(_base == null)
_base = Activator.CreateInstance<T>();
return _base;
}
}
public void Update(K item) { /* functionality for YourBaseObject */ }
public void Save(K item) { /* functionality for YourBaseObject */ }
public void Remove(K item) { /* functionality for YourBaseObject */ }
}
class Program
{
static void Main(string[] args)
{
var repository = new CustomerDataAccess();
Customer c = new Customer {
Age = 10,
EmailAddress = "this#demo.com"
};
repository.Save(c);
// This pass-through is no longer needed, but shown as example
// repository.BaseRepository.PerformCustomerOnlyAction(c);
repository.PerformCustomerOnlyAction(c);
}
}
NOTE I did the above code from scratch/memory. The generic type constraints may not work exactly as I have them.
ASP.NET 3.5 Unleashed by Stephen Walther has a couple of chapters on creating a repository pattern which is setup similarly to what you're trying to accomplish in Version 2. He also splits processing up between a business logic layer and a data access layer. Although the book is huge (nearly 2000 pages) and many of the code examples are redundant or better left as part of the CD, he goes pretty in-depth for beginner-to-intermediate range. It's available used on Amazon for around $25.
I think while implementing object model of your application you just have to ask yourself a number of questions as though you are make object design review of your collegue code.
Why CustomerAccessLayer implements interface? Is there will be a number of layers implementing this Interface. Or maybe you are expecting any polymorph behaviour from classes implements this interface? Or maybe you will separate interface to standalone module and will provide its functionality though any kind of service?
Why do you need BALCustomer class? Why you could not make calls directly to CustomerAccesLayer? And, have i already spoke about codesyle? :)
If DataRepository have a generic behaviour and will provide a number of AccessLayers throw Execute property why it is have its own methods?
I think could be continued... I hope you've catch my point?