Repository Pattern

Posts   
 
    
vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 17-Sep-2012 07:26:34   

Hi,

I am planning to implement repository patten targeting LLBLGenPro Self Servicing (v 3.5), MVC and VB.NET. I am sort of confused on how things would happen dynamically and wondering if you guys could provide me with a brief code or a sample project that uses LLBLGenPro and Repository pattern (Self servicing)?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 17-Sep-2012 17:09:46   

I am sort of confused on how things would happen dynamically

Could you please be more specific?

Also, please check these threads:

http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=15970

http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=21227

vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 18-Sep-2012 03:24:44   

For example if i want to implement the following code using self service llblgen pro v3.5.. How would it work? I am newbie to LLBLGen and not really sure. If i am creating this class of type let's say EntityClasses.TblSchool, then how would i use LinqMetaData because linqmetadata class expects an entity name at compile time. can i pass the name of the entity at runtime? would it work against type T which is determined at runtime?

Thanks

public class GenericRepository<TEntity> where TEntity : class { internal SchoolContext context; internal DbSet<TEntity> dbSet;

    public GenericRepository(SchoolContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 18-Sep-2012 06:47:49   

You could use metaData.GetQueryableForEntity(int typeOfEntity) and try to parse the generic parameter. However I don't know what you expect of that, since it would be kind of complicated to build real queries.

David Elizondo | LLBLGen Support Team
vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 19-Sep-2012 05:42:12   

i tried the suggestion you suggested and this is what i wrote:

Public Function FindById(id As Integer)
    Dim metadata As New LinqMetaData
    Dim datasource = metadata.GetQueryableForEntity(CType([Enum].Parse(GetType(EntityBase), GetType(T).Name), Integer))
    Return From p In datasource _
            Select p
End Function

but it comes up as saying that datasource is not queryable?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 19-Sep-2012 07:33:30   

This is an example on how to use it. This method returns an IQueryable for the entity passed in (this is for C#, sorry I forgot some syntax for VB):

public IQueryable<TEntity> GetQueryableForEntity<TEntity>() where TEntity : class
{
    var metaData = new LinqMetaData();
    return (IQueryable<TEntity>) metaData.GetQueryableForEntity((int) Enum.Parse(typeof(EntityType), typeof(TEntity).Name));
}

... and this is how you could use it:

// get the query
var q = GetQueryableForEntity<CustomerEntity>();
var q2 = from c in q
            where c.Country == "USA"
            select c;

// set the adapter and fetch it
var results = new List<CustomerEntity>();
using (var adapter = new DataAccessAdapter())
{
    ((LLBLGenProProvider2)((IQueryable)q).Provider).AdapterToUse = adapter;
    results = q.ToList();
}

I set the adapter outside the method, but you could create and use the adapter inside:

var metaData = new LinqMetaData(adapter);
David Elizondo | LLBLGen Support Team
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 19-Sep-2012 07:36:09   

This seems to be the equivalent for VB.Net (acording to http://converter.telerik.com):

Public Function GetQueryableForEntity(Of TEntity As Class)() As IQueryable(Of TEntity)
    Dim metaData = New LinqMetaData()
    Return DirectCast(metaData.GetQueryableForEntity(CInt([Enum].Parse(GetType(EntityType), GetType(TEntity).Name))), IQueryable(Of TEntity))
End Function

' get the query

Dim q = GetQueryableForEntity(Of CustomerEntity)()
Dim q2 = _
    Where c.Country = "USA"

' set the adapter and fetch it
Dim results = New List(Of CustomerEntity)()
Using adapter = New DataAccessAdapter()
    DirectCast(DirectCast(q, IQueryable).Provider, LLBLGenProProvider2).AdapterToUse = adapter
    results = q.ToList()
End Using
David Elizondo | LLBLGen Support Team
vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 19-Sep-2012 07:51:28   

Thanks mate. That seems to be working but just have another question stuck_out_tongue_winking_eye . The tentity type i am passing is a model class and not a LLBLGen entity. (i have one custom model class for each entity) and then i am implementing the generic repository class by passing the model classes. The query you posted will work if i pass an LLBLGenEntity. Is there something that can be done to make it work even if i pass a model class?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 19-Sep-2012 17:37:42   

Why are you using a model class, although Entity classes are built to be your model classes.

vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 20-Sep-2012 03:05:19   

because i want to display only certain amount of data to the user and entity classes have lots of information inside them. This was mentioned in one of the best practises for MVC. If i bind an entity class to a MVC UI and display only certain information and hide other information, there is a way for a user to hack through and see other hidden information. That's why i created a model class and displaying only what i need to. Is that right? This information is from Microsoft site itself. Please let me know if i am doing it wrong.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 20-Sep-2012 07:53:25   

You can pass an LLBLGen Entity type and return a custom model projection. I don't know if that is against the MS advice though.

If you want to pass your own model type to that method then you need a mechanism that return the LLBLGen Entity type you want to fetch based on the model type you pass. Something like:

var entity = GiveMeAnLLBLGenType(myModelType);
David Elizondo | LLBLGen Support Team
vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 20-Sep-2012 09:48:41   

I do have a mechanism to find the entitytype for each model class. but where do i pass that entitytype? This is what i am doing now

 Public Function Find( _
                  Optional filter As Expressions.Expression(Of Func(Of T, Boolean)) = Nothing) As IQueryable(Of T) Implements IRepository(Of T).Find
        Dim metaData As New LinqMetaData

        Dim dataSource = TryCast(metaData.GetQueryableForEntity(CInt([Enum].Parse(GetType(EntityType), GetEntityType.Name))), IQueryable(Of EntityBase))

        Dim q = From p In dataSource _
                Select AutoMapper.Mapper.Map(Of T)(p)

        'Dim datasource = GetQueryableForEntity(Of T)()

        If filter Is Nothing Then
            Return q
            'Else
            '   Return dataSource.Where(filter)
        End If

    End Function

Where GetEntityType returns the name of the entity which i am overriding in each repository class. but this function throws an when i try to return q

 at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.ProjectionListExpression.AddEntityFieldsToProjectionList(EntityExpression expressionToHandle, IElementCreatorCore creator, Int32 elementIndex) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionClasses\ProjectionListExpression.cs:line 334
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.ProjectionListExpression.AddExpressionElement(String elementName, Type elementType, Expression elementToAdd, Int32 elementIndex, IElementCreatorCore generatedCodeCreator, ITemplateGroupSpecificCreator frameworkElementCreator, MappingTracker trackedMappings, FunctionMappingsContainer functionMappings) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionClasses\ProjectionListExpression.cs:line 278
   at SD.LLBLGen.Pro.LinqSupportClasses.LinqUtils.CoerceLinqExpressionToProjectionListExpression(Expression toCoerce, IElementCreatorCore generatedCodeElementCreator, ITemplateGroupSpecificCreator frameworkElementCreator, MappingTracker trackedMappings, FunctionMappingsContainer functionMappings) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\LinqUtils.cs:line 2317
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleProjectionExpression(ProjectionExpression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\QueryExpressionBuilder.cs:line 2672
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\GenericExpressionHandler.cs:line 201
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\QueryExpressionBuilder.cs:line 141
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleSelectExpression(SelectExpression expressionToHandle, SelectExpression newInstance) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\GenericExpressionHandler.cs:line 817
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleSelectExpression(SelectExpression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\GenericExpressionHandler.cs:line 796
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleSelectExpression(SelectExpression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\QueryExpressionBuilder.cs:line 3200
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\GenericExpressionHandler.cs:line 207
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\ExpressionHandlers\QueryExpressionBuilder.cs:line 141
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\LLBLGenProProviderBase.cs:line 158
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.Execute(Expression expression) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\LLBLGenProProviderBase.cs:line 92
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\LLBLGenProProviderBase.cs:line 700
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.5\Frameworks\LLBLGen Pro\RuntimeLibraries\LinqSupportClasses\LLBLGenProQuery.cs:line 162
   at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 20-Sep-2012 19:12:36   

I think you should have a way to return an entity from the modelType object. Or am I missing something?

vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 21-Sep-2012 02:43:46   

This is what my one of the repository classes looks like. Each repository class overrides this function.

Protected Overrides Function GetEntityType() As System.Type Return GetType(Mail.DAL.EntityClasses.TblCostCentreEntity) End Function

Protected ReadOnly Property CostCentreEntity() As EntityClasses.TblCostCentreEntity
    Get
        Return CType(MyBase.DataObject, EntityClasses.TblCostCentreEntity)
    End Get
End Property

Then i use this in the Find function as described earlier.

the line in the find function where i doing meta.queryableforentity, datasource variable gets this value

SD.LLBLGen.Pro.LinqSupportClasses.DataSource(Of Mail.DAL.EntityClasses.TblCostCentreEntity) = {SD.LLBLGen.Pro.LinqSupportClasses.DataSource(Of Mail.DAL.EntityClasses.TblCostCentreEntity)}

and then i try to query and use the automapper to move it to the model class but then it throws the error as i attached before. If i don't use the automapper it returns the query fine but throws this error:

Unable to cast object of type 'SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1[Mail.DAL.EntityClasses.EntityBase]' to type 'System.Linq.IQueryable1[Mail.Model.CostCentreViewModel]'.

but i need to convert this to my model class? How else would i do that? Does the error i previously attached makes any sense to you? Please help. This is the main stage of my project, if i get it going, then everything else would flow on else i am stuck

--EDIT

It works this way but does not let me use my filter because it's of type ViewModel? Any workaround for this please?

Public Function FindS( _ Optional filter As Expressions.Expression(Of Func(Of T, Boolean)) = Nothing) As IEnumerable(Of T) Implements IRepository(Of T).FindS Dim metaData As New LinqMetaData

    Dim dataSource = TryCast(metaData.GetQueryableForEntity(CInt([Enum].Parse(GetType(EntityType), GetEntityType.Name))), IQueryable(Of EntityBase))

    Dim q = (From p In dataSource _
            Select p).ToList


    Return AutoMapper.Mapper.Map(Of IEnumerable(Of T))(q)


End Function
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 21-Sep-2012 06:09:06   

That makes sense, because you are materializing entities before use AutoMapper. So far so good. Now your filter. Did you try already the PredicateBuilderClass? (http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=14224)

David Elizondo | LLBLGen Support Team
vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 21-Sep-2012 07:55:05   

Thanks for your help guys.

The following code would fix these issues if anyone needs it.

 Public Function FindByCondition( _
           filter As Expressions.Expression(Of Func(Of T, Boolean))) As T Implements IRepository(Of T).FindByCondition
    Dim metaData As New LinqMetaData

    Dim compiled As Func(Of T, Boolean) = filter.Compile

    Dim dataSource = TryCast(metaData.GetQueryableForEntity(CInt([Enum].Parse(GetType(EntityType), GetEntityType.Name))), IQueryable(Of EntityBase))

    Dim q = (From p In dataSource _
            Select p).ToList



    Dim g = AutoMapper.Mapper.Map(Of IEnumerable(Of T))(q)

    For Each k As T In g
        Return g.FirstOrDefault(compiled)
    Next



End Function
vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 21-Sep-2012 09:25:26   

Another repository question. If an entity has a foreign key column, then how can i get all the values for that foreign key from it's primary table and return everything as one object?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 21-Sep-2012 13:52:25   

Do you mean by "one object", a flat object? Or a in a compostion way, i.e. order.Customer.Id ?

vivek
User
Posts: 45
Joined: 06-Sep-2012
# Posted on: 24-Sep-2012 07:00:26   

Sorry. ignore my last question. i have got it all sorted now.

Thanks for your help guys. Really appreciate it.