Circle reference (provider -> model -> provider) - vb.net

i'm creating a new way to do the things in my project and i need some help in some point.
I have 3 projects in my solution:
Buusiness, Provider and Model.
The MODEL project, is the one that i have the classes just like the tables in database:
Ex:
public class Person
property Id as integert?
property Name as string
property CPF as string
end class
the PROVIDER project, is the one that makes the communication with database:
public class PersonProvider
public function ListPerson(filter as model.person) as list(of model.person)
public sub insertPerson(byRef person as model.peson)
public sub updatePerson(byRef person as model.peson)
public sub deletePerson(byRef person as model.peson)
end class
and finally, i have the BUSINESS project, that's the project that exposes the CRUD methods to the website (the website must not have access to the PROVIDER, because we have business logic in the BUSINESS)
public class PersonBusiness
public function ListPerson(filter as model.person) as list(of model.person)
return (new provider.PersonProvider).listPerson(filter)
end public
public sub InsertPerson(byRef person as model.person)
dim provider as new provider.PersonProvider()
provider.insertPerson(person)
end public
...
end class
But, i have come to a problem when i need some inner joins like this:
table CUSTOMER have an id_person, so in model.Customer i have a property IdPerson as integer?
but i want to have the properties Name and CPF that the model.Person have, read only property in the model.Customer, so i've made:
Property IdPerson As Integer?
Private _person As Pessoa
Private ReadOnly Property Person As model.Person
Get
If IsNothing(_person) Then
_person = New provider.PersonProvider.ListPerson(new model.Person with {.Id = Me.IdPerson})
End If
Return _person
End Get
End Property
ReadOnly Property Name As String
Get
Return Me.Person.Name
End Get
End Property
ReadOnly Property CPF As String
Get
Return Me.Pessoa.CPF
End Get
End Property
and here comes the question... i found that i can't have reference like:
Website reference Model and Business
Provider reference Model
Business reference Model and Provider
but to do the readonly Properties the Model needs reference to Provider, and that causes a circle reference..visual studio doesn't allow me to do this...
any idea how to do this?
Sorry that my post become so long, i just wanted to make things clear.

Instead of accessing Model by Website and Business, you could add another class that references Provider and Person, and this new class will referenced by Website and Business (instead of Website and Business referencing Person directly).

Related

How to link a view to a model in vb.net code First

I've an old programm with edmx. Inside this one, I've linked a class (Table) To a View (Table/filter on a value of a column)
I want migrate this project to code first.
I copy/paste the project delete edmx file and generate models from an existing database.
All is good except this link.
<Table("JoinAffectation")>
partial public Class JointAffectation
public property Id as Long
public IdRecherche as Integer 'the link with my view
<NotMapped>
<ForeignKey("Id")>
PUBLIC OVERRIDABLE PROperty RechercheJoint as ViewRechercheJoint
But When I try to use function of automatical sort/filter using expression
I've error : The specified type member 'RechercheJoint' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
If I removed I error saying I don't same comumn and property... Also , How Can I stipulate RechercheJoint is mapped on IdRecherche
thanks for your help
Finally Using modelbuilder, I can join my view and my table like in edmx
<Table("JointAffectation")>
Partial Public Class JointAffectation
Public Property Id As Long
Public Property IdTypeJoint As Long
Public Property IdRecherche As Integer
Public Overridable Property JointType As JointType
<ForeignKey("Id")>
Public Overridable Property RechercheJoint As ViewRechercheJoint
End Class
<Table("ViewRechercheJoint")>
Partial Public Class ViewRechercheJoint
<Key>
<DatabaseGenerated(DatabaseGeneratedOption.None)>
Public Property Id As Integer
<StringLength(50)>
Public Property Libelle As String
<ForeignKey("IdRecherche")>
Public Overridable Property JointAffectations As ICollection(Of JointAffectation)
End Class
modelBuilder.Entity(Of JointAffectation)() _
.HasRequired(Function(e) e.RechercheJoint) _
.WithMany(Function(e) e.JointAffectations) _
.HasForeignKey(Function(e) e.IdRecherche)

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.

Custom Classes and Collection Classes

I have some custom classes and collection classes for those classes. I'm kind of new to actually implementing all of this, and I see a lot of different options but all with their own pros and cons, and I'm having trouble determining the best/right way to do what I need.
For example, I have a Product class with ID and Description properties. I have a ProductCollection class that I basically want to be a dictionary consisting of Product objects. This is a dictionary because there is a performance gain in accessing by key value, which is how I'll reference the objects. The key is Product.ID, and the value is Product.
I'd like to be able to do something like ProductCollection.Add(Product), and the collection will handle signing the dictionary key from the object's ID property. How do I best accomplish this? Implement Dictionary(Of Integer, Product) and override basically all methods to pass in the object and property separately? Or is there a better way?
Also, to give a little more background information to help clarify usage of these classes, there will be a "master" instance of ProductCollection containing all possible products. A ShipTo class will also have a ProductCollection containing specific products that are applicable for that particular ShipTo. My question was specific to the Product/ProductCollection classes, but also applied to the ShipTo classes.
This is how I would hold a collection of products. I have a Product class and a Products collection class.
First create the Product class which holds all the properties:
Imports System.Collections.ObjectModel
Public Class Product
Public Key As String
Public Sub New(ByVal id As Integer,
ByVal description As String)
_id = id
_description = description
End Sub
Private _id As Integer
Public ReadOnly Property ID() As Integer
Get
Return _id
End Get
End Property
Private _description As String
Public ReadOnly Property Description() As String
Get
Return _description
End Get
End Property
End Class
The create a Products collection class to hold the Product class:
Public Class Products
Inherits KeyedCollection(Of String, Product)
Protected Overrides Function GetKeyForItem(ByVal item As Product) As String
Return item.Key
End Function
End Class
You would then use these like this:
Dim myProducts As New Products
myProducts.Add(New Product(1,"Table"))

Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer)

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 :)