Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer) - vb.net

Please see the code below:
Imports Microsoft.VisualBasic
Public Class PersonBLL
Private Name As String
Private Age As Integer
Dim objPersonDAL As New PersonDAL
Dim objPerson As Person
Public Sub getPersonByID()
objPerson = objPersonDAL.getPersonByID()
MsgBox(objPerson.Name)
End Sub
End Class
Public Class PersonDAL
Private Name As String
Private Age As Integer
Public Function getPersonByID() As Person
'Connect to database and get Person. Return a person object
Dim p1 As New Person
p1.Name = "Ian"
p1.Age = 30
Return p1
End Function
End Class
Public Class Person
Private _Name As String
Private _Age As Integer
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Public Property Age() As Integer
Get
Return _Age
End Get
Set(ByVal value As Integer)
_Age = value
End Set
End Property
End Class
PersonBLL calls PersonDAL and returns a Person object. Is this the correct approach? i.e. I have identified a persistent class and created a corresponding DAL class with a function for accessing the data and returning the Person object.
There is a comment that states that this question is "subjective". I agree with this. I realise that the design depends on the requirements of the project. Are there any principles documented for designing a DAL similar to SOLID (single responsibility etc) etc.

Yes, your question demonstrates a very clean way to separate the logic into layers. The PersonBLL class would be part of the business layer, the PersonDAL class would be part of the data access layer, and the Person class would be part of the data transfer objects (DTO) layer. This is a very common way to separate your layers which works well in many situations.
My only recommendations would be:
You should put each layer in their own namespaces, if not also their own class library projects.
You should not show a message box from the business layer. I assume you only did this as a means of demonstration, but just in case, I thought I should mention it. Showing a message box should be part of the UI layer. For instance, if you were calling PersonBLL.getPersonByID from a windows service or a web service, showing a message box would be entirely inappropriate.
Typically, all methods are PascalCase, not camelCase. Some people prefer to make private methods camel case, but certainly public methods shouldn't be camel case.
Consider using dependency-injection techniques (DI) to inject the data access object into the business object.
Dependency Injection
Here's an example of how to do this with DI techniques:
Public Class BusinessFactory
Public Function NewPersonBusiness() As IPersonBusiness
Return New PersonBusiness(New PersonDataAccess())
End Function
End Class
Public Class PersonBusiness
Implements IPersonBusiness
Public Sub New(personDataAccess As IPersonDataAccess)
_personDataAccess = personDataAccess
End Sub
Private _personDataAccess As IPersonDataAccess
Public Function GetPersonByID() As PersonDto Implements IPersonBusiness.GetPersonByID
Return _personDataAccess.GetPersonByID()
End Sub
End Class
Public Interface IPersonBusiness
Function GetPersonByID() As PersonDto
End Interface
Public Interface IPersonDataAccess
Function GetPersonById() As PersonDto
End Interface
Public Class PersonDto
Private _name As String
Private _age As Integer
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Age() As Integer
Get
Return _age
End Get
Set(ByVal value As Integer)
_age = value
End Set
End Property
End Class
Doing it this way has many advantages. You can have multiple interchangeable data access layer implementations, so it's more flexible. Also, you can inject a fake data access object when you want to unit test the business class. DI design avoids many of the traps that lead to buggy, spaghetti code.
With DI, it is typically recommended that you ask for dependency objects as an interface rather than as a concrete type (e.g. IPersonDataAccess rather than PersonDataAccess). Doing so can be a little bit of a hassle, but you get use to it quickly. Since you are often, at that point, creating one interface for every class, it's convenient to just put the interface in the same code file as the class. So, for instance, PersonBusiness.vb would contain both the PersonDataAccess class and the IPersonDataAccess interface.
There are two reasons why using interfaces, rather than classes, for your dependencies is important:
It ensures that the design is flexible. You want to be able to override every public member of the dependency type so that you can create any kind of concrete implementation. There are other ways to do this. For instance, you could skip creating the IPersonDataAcess interface by simply marking every public property and method in the PersonDataAccess class with the Overrideable modifier, but there's nothing forcing you to do that. Even if you always remembered to do so, that doesn't mean someone else working on your code would know they should do that.
DI is often tied-in with unit testing because it is the best tool available for ensuring that code is testable. When unit testing, it is particularly important that you are able to override ever member in a dependency type so you can make a "fake" object that works just the way you need it to work in order to properly perform the unit test. These "fake" objects are called mocks.
You are being more technically honest about what your dependency is. In reality, you aren't really saying that your dependency is actually an instance of the PersonDataAccess class. In actuality, your dependency is any object that happens to have that same public interface. By asking for the class, you are implying that you need a particular implementation, which is a lie. If you have designed it properly, you only care about the interface being the same, so by asking only for the interface itself, you are specifying precisely what you mean to specify :)

Related

Generic Collection of T for ICollection of DbEntities

The Situation-
Have EF database entities with collections of other database entities as navigation properties all of which are not exposed outside of the project. Each of these entities are nested in base classes that allow public read and protected set access to the Db entity's property values and are the classes the business layer will work with. So these base classes also need collections of their Db entity's navigation properties.
What I have now-
I am still working on how I want the data layer to interact with with the other layers that reference it. So I have been experimenting with creating collection classes that can be set equal to a collection of Db entities and create a collection of the base class that the Db entity is nested in. The collection is then exposed outside the class though an interface as well as the base class. The interface gives access to some custom methods of collection class like accepting DTOs and prebuilt quires but would hide any Add methods.
The Problem-
I would like to create a generic base class for the collections but cant seem to find a way. I have gotten close to something workable but it was ugly and confusing. Below is an outline of what I'm working with. The narrowing operators in the entity class work well. I would rather have widening operators and narrowing operators in the base class so I could keep the New method private for the base classes but I don't want to expose the actual database entities outside the Data Layer.
Interops Namespace referenced by all projects in solution-
Public Interface IGenericEntity
End Interface
Public Interface INavigationPropertyEntity : Inherits IGenericEntity
End Interface
Public Interface IDbEntityToExposedEntityCollection(Of TEntity As IGenericEntity)
'Used to hide Add method
End Interface
Public Interface IPublicEntity
ReadOnly Property NavProps As IDbEntityToExposedEntityCollection(Of INavigationPropertyEntity)
End Interface
Data Layer project-
-Database Entities
Friend Class DbEntity1
Public Shared Narrowing Operator CType(ByVal value As DbEntity1) As NavigationPropertyEntity
Return New NavigationPropertyEntity(value)
End Operator
End Class
Friend Class DbEntity2
Public Sub New()
NavigationPropertyDbEntities = New HashSet(Of DbEntity1)
End Sub
Public Property NavigationPropertyDbEntities As ICollection(Of DbEntity1)
Public Shared Narrowing Operator CType(ByVal value As DbEntity2) As PublicEntity
Return New PublicEntity(value)
End Operator
End Class
-Exposed Base Classes
Public Class NavigationPropertyEntity : Implements INavigationPropertyEntity
Private _value As DbEntity1
Friend Sub New(value As DbEntity1)
_value = value
End Sub
End Class
Public Class PublicEntity : Implements IPublicEntity
Dim _value As DbEntity2
Friend _NavProps As DbEntityToPublicEntityCollection(Of INavigationPropertyEntity, DbEntity1, NavigationPropertyEntity)
Public ReadOnly Property NavProps As IDbEntityToExposedEntityCollection(Of INavigationPropertyEntity) Implements IPublicEntity.NavProps
Get
Return _NavProps
End Get
End Property
Friend Sub New(value As DbEntity2)
_value = value
_NavProps = new DbEntityToPublicEntityCollection(Of INavigationPropertyEntity, DbEntity1, NavigationPropertyEntity)(_value.NavigationPropertyDbEntities)
End Sub
End Class
-Entity Specific Collection
Friend Class DbEntityToPublicEntityCollection(Of IEnt As INavigationPropertyEntity, DbEnt As DbEntity1, ExpEnt As NavigationPropertyEntity)
Inherits HashSet(Of IEnt)
Implements IDbEntityToExposedEntityCollection(Of IEnt)
Public Sub New(value As HashSet(Of DbEnt))
For Each ent In value
Dim exp As NavigationPropertyEntity = ent
Dim i As INavigationPropertyEntity = exp
MyBase.Add(i)
Next
End Sub
End Class
Additional Info Edit
The main issue is being able to have a generic collection declared something like,
Friend Class DbEntityToPublicEntityCollection(Of IEnt, DbEnt as class, ExpEnt As class)
because in the New sub ExpEnt cannot be converted to DbEnt and a TryCast will just result in a runtime error.
Like I said, I tried setting up classes that are inherited by the exposed and entity classes so a new method with a parameter for the exposed class could be set up but with trying to have the interfaces in there it got unmanageable pretty quick. Then again I have not worked much with making my own generic types before so I'm not sure if this is even a proper strategy.

How To Access A Shared Property Of A Class Passed As A Type Parameter

I'm trying to access a shared property of a class passed as a parameter to a type-parametrised procedure. The reason why I'm doing this is so I can embed the various API call endpoints (among other class-specific things) as properties within the class itself. I've read some similar SO posts but nothing is close enough to be sure that it isn’t possible (which I think is likely).
Below is the essence of the structure - there's some pseudo code towards the end:
MustInherit Class BaseClass
Shared Property Endpoint As String
End Class
Class Person
Inherits BaseClass
Property Age As Integer
Property Name As String
Sub New()
_Endpoint = "/GetPerson"
End Sub
End Class
Class Event
Inherits BaseClass
Property When As Date
Property Type As String
Sub New()
_Endpoint = "/GetEvent"
End Sub
End Class
Function Retrieve(T As BaseClass)(Id As String) As T
Dim oResp As HttpResponse = MakeGetCall(T.Endpoint, Id) <- T.Endpoint throws a compile error
Return Deserialize(Of T)(oResp.Content)
End Function
Dim oPerson As Person = Retrieve(Of Person)("123")
Dim oEvent As Event = Retrieve(Of Event)("123")
To my tiny mind, I would have thought that, since T’s base class is BaseClass which contains the property Endpoint, I’d be ok. But seemingly not.
I've tried a fair few things from here on SO and other places to overcome this to no avail. Yes, I realize I could perform some kind of endpoint look-up based on the type of T but the above represents a very clean solution and I’d like to get it to work if possible.
Any ideas?
Assuming you want EndPoint to be different for each subclass, you should use MustOverride instead of Shared...
MustInherit Class BaseClass
Public MustOverride Property EndPoint As String
End Class
Then return a constant in each subclass
Class Person
Inherits BaseClass
Public Overrides Property EndPoint As String
Get
Return "/Person"
End Get
You might want to declare EndPoint as ReadOnly too.
The small limitation is that you'll need an instance of the class to access EndPoint (since it isn't Shared). If you have a parameterless constructor, you could use (New Person).EndPoint where needed.

How do I refer to two different classes by one name in vb.net

I have two classes to handle database operations, one for MySQL (DBMySQL), and another for SQLite (DBSQLite). The user chooses which database system to use.
The functions within the classes have the same names, but are obviously slightly different to handle the variations in databases.
I would like to refer to the chosen class by one name throughout the application. I have set a global variable DB.
In a procedure I can: Dim DB as New DBMySQL (or DBSQLite). This works within the procedure, but not globally, but I can see all the functions when coding.
If I instead use: DB = New DBMySQL, this works globally, but no class functions are displayed when coding.
Any alternatives?
Use the concept of inheritance, and create a MustInherit class with MustOverride methods and/or properties.
Public MustInherit Class AbstractDB
Public MustOverride Function MyQuery(input As Object) As Object
Public MustOverride Sub MyUpdateMethod(input As Object)
End Class
Public Class DBMySQL
Inherits AbstractDB
Public Overrides Function MyQuery(input As Object) As Object
End Function
Public Overrides Sub MyUpdateMethod(input As Object)
End Sub
End Class
Public Class DBSQLite
Inherits AbstractDB
Public Overrides Function MyQuery(input As Object) As Object
End Function
Public Overrides Sub MyUpdateMethod(input As Object)
End Sub
End Class
Then, when you want to use your classes, make your DB global variable of type AbstractDB. You could then create either DBMySql or DBSQLite and assign it to your DB variable. The method names will all be the same, because they all inherit the same base class. But each derived class must fill out the content of those methods on its own.
Dim DB as AbstractDB = New DBMySQL
You could also use an interface.
Public Interface IRepository
' common functions of MySQL and SQLLiteclasses
End Interface
Public Class MySQLRepository
Implements IRepository
End Class
Public Class SQLLiteRepository
Implements IRepository
End Class
Public Function GetDB(userChoice As String) As IRepository
If userChoice = "MySQL" Then
Return New MySQLRepository()
Else
Return New SQLLiteRepository
End if
End Function
Dim DB As IRepository = GetDB(userChoice)
This is a basic implementation of the Repository pattern. The example in the link is in C#, but, as you're probably aware, it's not easy finding examples in VB. Fortunately, there are lots of C# to VB converters.
The abstract example Sean Skelly gave should also work. You may want to research the difference between abstract classes and interfaces.

Make static member persistent

I have one class with a private static (shared, since I'm in VB.BET) field and its associated public static property, since it stores one variable that should be the same to all the instances of this class.
My Class looks like this:
Public MustInherit Class NitrogenController
Private _active As Boolean
Private Shared _controlInterval As TimeSpan
Private _lastControlTime As Date
Public Property Active() As Boolean
Public Shared Property ControlInterval() As System.TimeSpan
'other properies that must be persisted
Public Function Control() As Boolean
If Not Now > _lastControlTime.Add(_controlInterval) Or Not _active Then
Return False
Else
DoControl()
_lastControlTime = Now
Return True
End If
End Function
End Class
The problem arrives when trying to binary serialize these kind of objects, since this shared field is nos being properly stored and returns to its default value when deserializing.
I suppose this is the expected behaviour, so my question is... how can I make a shared field persistent? I have read some comments to similar questions that say that this is a bad design, but it really makes sense (AFAIK) in my case, since this variable should be the same to all the object, but can be changed by the user and therefore should be stored.
Can you suggest another way of doing it?
Thanks!
What you have read, in my opinion, is correct. This is, likely, a bad design. However, if you must, there are two ways to do this with the XmlSerializer. The easy way would be to simply add a public instance (non-shared) property which has a getter and setter which simply wrap the shared property, for instance:
Public MustInherit Class NitrogenController
Public Shared Property ControlInterval As TimeSpan
Public Property CurrentControlInterval() As TimeSpan
Get
Return ControlInterval
End Get
Set(value As TimeSpan)
ControlInterval = value
End Set
End Property
End Class
If you aren't satisfied with that method, the second, more involved, option would be to override the default serialization logic by implementing the ISerializable interface.

Using polymorphism on member of interface

Okay this is a bit of a noobish question, but I ran across this today and it somewhat puzzles me WHY it would be this way.
Consider the following structure
Public Class Employee
Implements IPerson
Private _MyManager As Manager
Public Property MyManager() As Manager Implements IPerson.TheirLeader
Get
Return _MyManager
End Get
Set(ByVal value As Manager)
_MyManager = value
End Set
End Property
End Class
Public Class Manager
Implements IPerson, IAuthorityFigure
Private _MyBoss As Boss
Public Property MyBoss() As Boss Implements IPerson.TheirLeader
Get
Return _MyBoss
End Get
Set(ByVal value As Boss)
_MyBoss = value
End Set
End Property
End Class
Public Class Boss
Implements IPerson, IAuthorityFigure
'Implementation code here...
End Class
Public Interface IPerson
Property TheirLeader() As IAuthorityFigure
End Interface
Public Interface IAuthorityFigure
'Stuff here...
End Interface
Here is my question: I am wanting to have every person implement the IPerson interface, whether they are an employee, boss, or manager. However, they each have an attribute that refers to their leader (employees have a manager, managers have a boss, etc). Each implementation of their leader could be potentially differnt other than they fact that they implement the IAuthorityFigure interface. I am wanting to have the IPerson interface have a property for the IAuthorityFigure, but it throws a compiler error for me when I implement this b/c the IAuthorityFigure is not the same type as Boss or Manager (even though they implement the interface).
So, I am doing something wrong, or is this a limitation of using interfaces versus abstract classes. If this is a limitation, can anyone explain why it is so?
Thanks!
You're not doing anything wrong. In all currently released versions of Visual Basic (and C#), the implementation of method, property or field of an interface must exactly match the signature on the interface. There is no way to override this.
The best that you can do is to have 2 properties, one which implmeents the interface and another which is used to return the actual implementation.
Private _MyBoss As Boss
Public Property TheirLeader() As IAuthorityFigure Implements IPerson.TheirLeader
Get
Return MyBoss
End Get
Set(ByVal value As IAuthorityFigure)
MyBoss = CType(value, IAuthorityFigure)
End Set
End Property
Public Property MyBoss As Boos
Get
Return _MyBoss
End Get
Set(ByVal value As Boss)
_MyBoss = value
End Set
End Property
It would help if you listed the code defining the IPerson interface. However, I would guess that you need to cast the Manager and Boss as IAuthorityFigure instead of their classes.