Ok... So I have created my model using EF4. Great!
I then turned off the code generation and downloaded this extension: http://visualstudiogallery.msdn.microsoft.com/23df0450-5677-4926-96cc-173d02752313
(POCO Entity Generator). Awesome!
Ran it, and it generates all of my classes. Is that all I have to do? It seems to work, my repositories get to the objects and persist to the DB.
Please have a look at the following code and let me know if I am on the right track.
** Sample Code **
Controller:
Namespace Controllers
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Return View(New Models.HomeModel)
End Function
End Class
End Namespace
Model:
Namespace Models
Public Class HomeModel
Private _Repository As Titan.Business.Repositories.ICustomerRepository
Private _SalesRepRepo As Titan.Business.Repositories.ISalesRepresentativeRepository
Public Property Customers As IEnumerable(Of Titan.Business.Customer)
Public Property SalesReps As IEnumerable(Of Titan.Business.SalesRepresentative)
Public Sub New()
_Repository = New Titan.Business.Repositories.CustomerRepository
_SalesRepRepo = New Titan.Business.Repositories.SalesRepresentativeRepository
_Customers = _Repository.Query(Function(x) x.LastName.StartsWith("Str"))
_SalesReps = _SalesRepRepo.Query(Function(x) x.LastName.StartsWith("Str"))
End Sub
End Class
End Namespace
Repository and Interfaces:
Namespace Repositories
Public Interface IRepository(Of T)
Function Query(ByVal Predicate As System.Linq.Expressions.Expression(Of Func(Of T, Boolean))) As IEnumerable(Of T)
Function GetByID(ByVal ID As Integer) As T
Sub Add(ByVal Entity As T)
Sub Delete(ByVal Entity As T)
Sub Save(ByVal Entity As T)
End Interface
Public Interface ICustomerRepository
Inherits IRepository(Of Customer)
End Interface
Public Interface ISalesRepresentativeRepository
Inherits IRepository(Of SalesRepresentative)
End Interface
End Namespace
Namespace Repositories
Public Class SalesRepresentativeRepository
Implements ISalesRepresentativeRepository
Public Sub Add(ByVal Entity As SalesRepresentative) Implements IRepository(Of SalesRepresentative).Add
End Sub
Public Sub Delete(ByVal Entity As SalesRepresentative) Implements IRepository(Of SalesRepresentative).Delete
End Sub
Public Function GetByID(ByVal ID As Integer) As SalesRepresentative Implements IRepository(Of SalesRepresentative).GetByID
End Function
Public Function Query(ByVal Predicate As System.Linq.Expressions.Expression(Of System.Func(Of SalesRepresentative, Boolean))) As System.Collections.Generic.IEnumerable(Of SalesRepresentative) Implements IRepository(Of SalesRepresentative).Query
Using db As New GTGContainer
Return db.SalesRepresentatives.Where(Predicate).ToList
End Using
End Function
Public Sub Save(ByVal Entity As SalesRepresentative) Implements IRepository(Of SalesRepresentative).Save
End Sub
End Class
End Namespace
Any suggestions would be so helpful to me.
Where does the service layer fit in?
What about the AutoMapper? Do I even need to use that now?
Dependency Injection? Anyone care to explain.
Thanks a bunch,
Sam
There's a great article by Scott Allen about Testing Entity Framework 4 - creating the POCO classes is a good first step, but if you want to test you business layer separate from EF you will have to introduce a Unit of Work that coordinates saving state across multiple repositories and allows DI.
Related
I'm trying to use interfaces for my Entities and Repositories but I can't seem to overcome a type conversion error. I have simplified the code to the basic minimum to reproduce this error.
'The entity interface
Public Interface IEntity
Property ID As Int32
End Interface
'A base class for new entities
Public MustInherit Class EntityBase
Implements IEntity
Public Property ID As Integer Implements IEntity.ID
End Class
'The repository interface
Public Interface IRepository(Of IEntity)
Function Load(ID As Int32) As IEntity
End Interface
'The base class for the repository
Public Class RepositoryBase(Of IEntity)
Implements IRepository(Of IEntity)
Public Overridable Function Load(ID As Integer) As IEntity Implements IRepository(Of IEntity).Load
Throw New NotImplementedException()
End Function
End Class
'An object using the entities base class
Public Class Person
Inherits EntityBase
Property Name As String
End Class
'An object using the repository base class
Public Class PersonRepository
Inherits RepositoryBase(Of Person)
Public Overrides Function Load(ID As Integer) As Person
Dim myPerson As New Person
'Do stuff for loading a Person
Return myPerson
End Function
End Class
'And here is some code to execute this all
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim PersonRepo As New PersonRepository
Dim TestWithType As IRepository(Of IEntity)
TestWithType = PersonRepo '<-- error goes here
End Sub
End Class
Intellisense doesn't give any error. The error only pops up when executing the code. The exact error is in Dutch:
Kan een object van het type Generic_Interface_test.PersonRepository
niet converteren naar het type
Generic_Interface_test.IRepository`1[Generic_Interface_test.IEntity].
So the PersonRepository cannot be converted to an IRepository type. But the PersonRepository class is based on the RepositoryBase which implements the IRepository interface.
What am I doing wrong here? In my final solution I want to drop my repositories into a dictionary but that seems impossible due to this error.
Update 1: The problem seems to be in the IEntity part. IRepository(Of IEntity) != IRepository(Of Person) while Person = IEntity.
Is there any way to create a list like List(Of IRepository(Of IEntity)) that actually works?
Update 2: I like the animal example of Tim so I will try to explain my question with animals.
Assume I have an interface IAnimal that I will use in another interface IRepository(Of IAnimal). For this type I will create a list Animals = List(Of IRepository(Of IAnimal)) where I can store repositories for all animals. Now I will create a class Lion based on the IAnimal interface and create a repository LionRepo based on IRepository(Of Lion). When I try to store LionRepo into Animals it fails because it expects IRepository(Of IAnimal) while my LionRepo is actually IRepository(Of Lion). But since Lion is based on IAnimal shouldn't this suppose to be working?
Trying to get my head around generic interfaces and classes. How do I 'get T' when using my class in the new method and call data.method using this type?
Public MustInherit Class RepositoryBase(Of T)
Implements IRepository(Of T)
Private Data As IDAL
Public Sub New()
Data = DTOParserFactory.GetParser(T.GetType().ToString())
End Sub
Public Sub delete(BaseDTO As T) Implements Domain.Business.IRepository(Of T).delete
'Data.delete(Convert.ChangeType(BaseDTO, TypeOf(Type))
End Sub
Public Function getAll() As System.Linq.IQueryable(Of T) Implements Domain.Business.IRepository(Of T).getAll
'Return Data.getAll()()
End Function
End Class
I'm assuming you need to get the Type object for T?
In your constructor
Public Sub New()
Data = DTOParserFactory.GetParser(GetType(T).ToString())
End Sub
I'm not super clear on the question, but perhaps this is what you are looking for.
Assuming you have a common base class BaseDTO then you would define your RepositoryBase class like this:
Public MustInherit Class RepositoryBase(Of T As BaseDTO)
Then you declare an instace of the class like this:
Dim userRepository As New RepositoryBase(Of User)()
What this does is constrain T to be a subclass of BaseDTO, and gives you access to all of BaseDTO's methods.
In our current project I am using a generic interface iService which is inherited by all other service interfaces. For instance IService is inherited by ILogService.
The ILogService interface is then implemented by LogService as below:
Public Interface IService(Of T)
Sub Save(ByVal T As IEntity)
Sub Remove(ByVal T As IEntity)
Function FindBy(ByVal Id As Guid) As T
Function FindAll() As IEnumerable(Of T)
End Interface
Public Interface ILogService
Inherits IService(Of Log)
Function FindLogsByOwner(ByVal Owner As Guid, ByVal visibility As LogVisibility) As IList(Of Log)
Function FindAllLogsByVisibility(ByVal visibility As LogVisibility) As IList(Of Log)
Function FindAllLogsByType(ByVal type As LogType) As IList(Of Log)
End Interface
Public Class LogService
Implements ILogService
Public Function FindAll() As System.Collections.Generic.IEnumerable(Of Model.CSLS.Log) Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).FindAll
End Function
Public Function FindBy(Id As System.Guid) As Model.CSLS.Log Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).FindBy
End Function
Public Sub Remove(T As Infrastructure.Domain.IEntity) Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).Remove
End Sub
Public Sub Save(T As Infrastructure.Domain.IEntity) Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).Save
End Sub
Public Function FindAllLogsByType(type As Model.CSLS.LogType) As System.Collections.Generic.IList(Of Model.CSLS.Log) Implements Model.CSLS.ILogService.FindAllLogsByType
End Function
Public Function FindAllLogsByVisibility(visibility As Model.CSLS.LogVisibility) As System.Collections.Generic.IList(Of Model.CSLS.Log) Implements Model.CSLS.ILogService.FindAllLogsByVisibility
End Function
Public Function FindLogsByOwner(Owner As System.Guid, visibility As Model.CSLS.LogVisibility) As System.Collections.Generic.IList(Of Model.CSLS.Log) Implements Model.CSLS.ILogService.FindLogsByOwner
End Function
End Class
Help Needed: I am trying to understand that when I am implementing ILogService interface I still get the functions/subs in the LogService class containing:
method parameter T of Type IEntity instead of Log
How can I update the method signature so T is displayed as Log?
What am I doing wrong?
Are you talking about these?
Sub Save(ByVal T As IEntity)
Sub Remove(ByVal T As IEntity)
This is very confusing, because in the above methods T is the name of a method parameter, not a generic type parameter. It could just as easily have been foo or bar. In each case the type of T is IEntity.
If the intention here was that Save and Remove should each accept an argument of type T, but that type T must implement IEntity, this is how you would express that:
Public Interface IService(Of T As IEntity)
Sub Save(ByVal entity As T)
Sub Remove(ByVal entity As T)
Function FindBy(ByVal Id As Guid) As T
Function FindAll() As IEnumerable(Of T)
End Interface
#DanTao is correct if that is the intention. If, however, you just intended the name of the method parameter to be specified by the generic type, that is not possible.
However, you can specify any name you like in the implementing method, so you can use Log if you want, but you can't enforce it (and some FxCop rule will warn you haven't used the same parameter name as specified in the interface).
Ok, so I was playing around with Ninject, a "Service Layer" and a "Repository Layer".
I built a simple console application to to play around, this is what I came up with:
Imports Ninject
Module Module1
Sub Main()
Dim Kernel As IKernel = New StandardKernel(New CustomerModule)
Dim Service = Kernel.Get(Of CustomerService)()
Console.WriteLine(Service.GetCustomerByID(1).Name)
Console.Read()
End Sub
End Module
#Region "Services"
Public Class CustomerService
Private _Repository As ICustomerRepository
<Inject()> _
Public Sub New(ByVal Repository As ICustomerRepository)
_Repository = Repository
End Sub
Public Function GetCustomerByID(ByVal ID As Integer) As Customer
Return _Repository.GetByID(ID)
End Function
End Class
#End Region
#Region "Repositories"
Public Interface IRepository(Of T)
Function Query(ByVal Predicate As Expressions.Expression(Of Func(Of T, Boolean))) As IQueryable(Of T)
Function GetByID(ByVal ID As Integer) As T
End Interface
Public Interface ICustomerRepository
Inherits IRepository(Of Customer)
End Interface
Public Class CustomerRepository
Implements ICustomerRepository
Public Function GetByID(ByVal ID As Integer) As Customer Implements IRepository(Of Customer).GetByID
Return New Customer With {.ID = ID, .Name = "Sam Striano"}
End Function
Public Function Query(ByVal Predicate As System.Linq.Expressions.Expression(Of System.Func(Of Customer, Boolean))) As System.Linq.IQueryable(Of Customer) Implements IRepository(Of Customer).Query
Return Nothing
End Function
End Class
#End Region
#Region "Domain Objects"
Public Class Customer
Public Property ID As Integer
Public Property Name As String
End Class
#End Region
#Region "Ninject Modules"
Public Class CustomerModule
Inherits Modules.NinjectModule
Public Overrides Sub Load()
Bind(Of ICustomerRepository).To(Of CustomerRepository)()
End Sub
End Class
#End Region
My question, or I guess my lack of understanding, lies in Main() method of the module:
Sub Main()
Dim Kernel As IKernel = New StandardKernel(New CustomerModule)
Dim Service = Kernel.Get(Of CustomerService)()
Console.WriteLine(Service.GetCustomerByID(710615).Name)
Console.Read()
End Sub
Why not just do this:
Sub Main()
Dim Service = New CustomerService(New CustomerRepository)
Console.WriteLine(Service.GetCustomerByID(710615).Name)
Console.Read()
End Sub
Basically, you are asking why you should use a DI Container instead of Pure DI.
DI is really just a set of principles and patterns that enable loose coupling. You can use those patterns to compose an application irrespective of any particular container.
However, as an application grows in complexity, and particularly when you need to manage differing lifestyles of your components, a DI Container is an excellent tool that addresses many issues that you'd otherwise have to address manually.
Dependency injection lets you decouple specific implementations of objects from their interfaces. It is difficult to justify in most of the small examples out there, but for larger systems it can be a life-saver. It can also help you to isolate your objects in unit tests.
For example, if you wanted to write tests for your CustomerService class, you could easily inject a MockRepository instead of CustomerRepository. This would let you test CustomerService without also testing CustomerRepository.
Outside of unit testing, I think the easiest example to visualize might be if you were writing a data access module for your application. You might want to support SQL Server and MySQL. You would then create Interfaces for your data access objects and create specific implementations of them for both database systems. Those implementations could be injected at runtime, thusly:
Function Setup(ByVal dbType As String) As IKernel
Dim dbModule As NinjectModule
If dbType = "SQL Server" Then
dbModule = New SQLServerModule
Else If dbType = "MySQL" Then
dbModule = New MySQLModule
End If
Return New StandardKernel(dbModule)
End Function
This also enables you to add support for other databases in the future, isolating the implementation details from the rest of the application.
I have two classes:
Public Class Subscribing
Private _subscribingObjects As IList(Of String)
Public Sub Add(ByVal obj As SubscribeObject)
'...code...'
End Sub
Public Sub Remove(ByVal index As Integer)
'...code...'
End Sub
End Class
Public Class Providing
Private _providingObjects As IList(Of String)
Public Sub Add(ByVal obj As ProvideObject)
'...code...'
End Sub
Public Sub Remove(ByVal index As Integer)
'...code...'
End Sub
End Class
Is there a more elegant way to add do this? One class would suffice, but since the Add methods have different arguments, then one really wouldn't work.
Any help would be appreciated.
this?
Public Class SubscribingProviding(Of t)
Private _subscribingObjects As IList(Of String)
Public Sub Add(ByVal obj As t)
'...code...'
End Sub
Public Sub Remove(ByVal index As Integer)
'...code...'
End Sub
End Class
Your add functions should be fine. As long as you have different variable types being passed in you can have the function names be the same. Your remove Subs will not be allowed in the same class because it is using the same parameter Integer.
Eh.. probably not. They are different enough that you cant even Interface them.
I personally wouldn't mix the two responsibilities (of subscribing and providing) in one class. The classes themselves can easily be simplified by just inheriting from List(Of T)
Public Class Subscribing
Inherits List(Of SubscribeObject)
End Class
Public Class Providing
Inherits List(Of ProvideObject)
End Class
If you really want to get down to one class and make sure that it can only accept SubscribeObject and ProvideObject respectively, implement a common interface in both SubscribeObject and ProvideObject. Then create a generic class that accepts the interface:
' Common interface '
Public Interface ISubscribeProvideObject
End Interface
' SubscribeObject and ProvideObject both implementing the common interface '
Public Class SubscribeObject
Implements ISubscribeProvideObject
'...'
End Class
Public Class ProvideObject
Implements ISubscribeProvideObject
'...'
End Class
' Generic class accepting both types '
Public Class SubscribingProviding(Of T As ISubscribeProvideObject)
Inherits List(Of T)
'... Add() and Remove() methods only needed if custom logic applies ...'
End Class