This is a migrated thread and some comments may be shown as answers.

Fetch strategy not working for Generated Data Access Repositories for WebAPI

6 Answers 92 Views
Getting Started
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
pomi
Top achievements
Rank 1
pomi asked on 09 Jun 2014, 03:56 PM

Hello

I am having problem with Include() and FetchStrategies.

What did i do :

-  Following database first approach, Created a Domain Model using Telerik Data Access. This resulted in 'rlinq' file.
-  Since I was going to implement repository pattern and the quickest way I found with Telerik Data Access was that, I right click the rlinq file, and select "Create Telerik Data Access Service...'
-  

Now I have e.g. an autogenerated entity by the rlinq file

01.public partial class Approval
02.{
03.    private long _approvalId;
04.    public virtual long ApprovalId
05.    {
06.        get
07.        {
08.            return this._approvalId;
09.        }
10.        set
11.        {
12.            this._approvalId = value;
13.        }
14.    }
15.     
16.    private long? _clientId;
17.    public virtual long? ClientId
18.    {
19.        get
20.        {
21.            return this._clientId;
22.        }
23.        set
24.        {
25.            this._clientId = value;
26.        }
27.    }
28.     
29.    private string _subscriptionId;
30.    public virtual string SubscriptionId
31.    {
32.        get
33.        {
34.            return this._subscriptionId;
35.        }
36.        set
37.        {
38.            this._subscriptionId = value;
39.        }
40.    }
41. 
42.    private Company _company;
43.    public virtual Company Company
44.    {
45.        get
46.        {
47.            return this._company;
48.        }
49.        set
50.        {
51.            this._company = value;
52.        }
53.    }
54. 
55.    private IList<Calling> _callings = new List<Calling>();
56.    public virtual IList<Calling> Callings
57.    {
58.        get
59.        {
60.            return this._callings;
61.        }
62.    }

I the base repository interface (note this is also auto generated)

1.public interface IOpenAccessBaseRepository<TEntity, TContext> where TContext : OpenAccessContext, new()
2.{
3.    IQueryable<TEntity> GetAll();
4.    TEntity GetBy(Expression<Func<TEntity, bool>> filter);
5.    TEntity AddNew(TEntity entity);
6.    TEntity Update(TEntity entity);
7.    void Delete(TEntity entity);
8.}

Concrete implementation of above base repository, all other repositories are derived from this base repository (from the base repository, i am pasting implementation of only two GET functions for brevity)

01.    public abstract partial class OpenAccessBaseRepository<TEntity, TContext> : IOpenAccessBaseRepository<TEntity, TContext> where TContext : OpenAccessContext, new()
02.    {
03.        protected TContext dataContext = new TContext();
04.        protected FetchStrategy fetchStrategy = new FetchStrategy();
05. 
06.        public IQueryable<TEntity> GetAll()
07.        {
08.            List<TEntity> allEntities = dataContext.GetAll<TEntity>().ToList();
09. 
10.            List<TEntity> detachedEntities = dataContext.CreateDetachedCopy<List<TEntity>>(allEntities, fetchStrategy);
11. 
12.            return detachedEntities.AsQueryable();
13.        }
14. 
15.        public TEntity GetBy(Expression<Func<TEntity, bool>> filter)
16.        {
17.            if (filter == null)
18.                throw new ArgumentNullException("filter");
19. 
20.            TEntity entity = dataContext.GetAll<TEntity>().SingleOrDefault(filter);
21.            if (entity == null)
22.                return default(TEntity);
23. 
24.            TEntity detachedEntity = dataContext.CreateDetachedCopy(entity, fetchStrategy);
25. 
26.            return detachedEntity;
27.        }
28.}

A Derived Repository from the above Base Repository
01.public partial class ApprovalRepository : OpenAccessBaseRepository<Approval, VizAppModel>
02.{
03.     public new IQueryable<Approval> GetAll()
04.    {
05.        this.fetchStrategy.LoadWith<Approval>(a => a.Company);
06.        List<Approval> allEntities = dataContext.GetAll<Approval>().ToList();
07. 
08.        List<Approval> detachedEntities = dataContext.CreateDetachedCopy<List<Approval>>(allEntities, fetchStrategy);
09. 
10.        return detachedEntities.AsQueryable();
11.    }
12. 
13.}

PROBLEM NOTE : the above repository is never actually used, this new GetAll() function is never called, instead GetAll() function from the base repository is called by the program. I am using a Service Layer, this is simple class calling from repositories as follows:

The Service Classes derive from an Interface as follows:
01.public interface IVizAppService<TEntity, TContext> where TContext : OpenAccessContext, new ()
02.{
03.    IQueryable<TEntity> GetAll(string sid);
04.    TEntity GetById(object id, string sid);
05.    TEntity AddNew(TEntity entity, string sid);
06.    TEntity Update(TEntity entity);
07.    void Delete(TEntity entity);
08.    void HardDelete(TEntity entity);
09.}

Concrete implementation of this IVizAppService .... the methods in this class are called by controllers directly
01.public class ApprovalService : IVizAppService<Approval, VizAppModel>
02.{
03.    protected IOpenAccessBaseRepository<Approval, VizAppModel> service;
04. 
05.    public ApprovalService()
06.    {
07.        this.service = new ApprovalRepository();
08.    }
09.    public ApprovalService(IOpenAccessBaseRepository<Approval, VizAppModel> service)
10.    {
11.        this.service = service;
12.    }
13. 
14.     
15.    public IQueryable<Approval> GetAll(string sid)
16.    {
17.        return service.GetAll()
18.            .Where(i => i.SubscriptionId == sid && i.IsActive == true);
19.    }
20. 
21.    public Approval GetById(object id, string sid)
22.    {
23.        if (id == null)
24.        {
25.            throw new ArgumentNullException("id");
26.        }
27.        return service.GetAll().Include(i => i.Company)
28.             .SingleOrDefault(i => i.ApprovalId == (long)id);
29.    }


PROBLEM THAT I AM FACING AND CANNOT SOLVE = FETCHSTRATEGY OR 'INCLUDE' NOT WORKING
 
my GetAll methods in above service class, despite using 'Include' still cant get related entity 'Company' in the calls. I have tried a lot using fetch strategy but I know there is something wrong with the architecture or i just cant get my head around it. Most of the code is boilercode which is added automatically.

PLEASE HELP ..... If i could drop the service layer and use Enity Repository directly, i would gladly do so, but since i cant get 'repository class' to reference in my controllers, i used this above service layer.

Thanks for your help

Ali










6 Answers, 1 is accepted

Sort by
0
Boris Georgiev
Telerik team
answered on 12 Jun 2014, 03:58 PM
Hi Ali,

There is no need to override GetAll() method to introduce a FetchStrategy to the endpoint. To implement and use a FetchStrategy for a controller you should write the default constructor for the Repository in a partial class and define the FetchStrategy declared in the base class OpenAccessBaseRepository.

In your case it should looks like:
1.public partial class ApprovalRepository
2.{
3.    public ApprovalRepository()
4.    {
5.        this.fetchStrategy.LoadWith<Approval>(a => a.Company);
6.    }
7.}

Thus the GetAll() method from the OpenAccessBaseRepository class will use the defined FetchStrategy from the inherited class - ApprovalRepository.

I hope that helps.

Regards,
Boris Georgiev
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
pomi
Top achievements
Rank 1
answered on 13 Jun 2014, 02:49 PM
Hello Boris

Thanks for your reply, Yes! this does solve the problem, now i am able to use the fetchStrategy. 

Many Thanks

Regards,
Ali
Webify Asia
0
pomi
Top achievements
Rank 1
answered on 09 Jul 2014, 02:29 PM
Hello Boris

As usual with Telerik, the reply you posted helped very well with our solution, however I stumble upon yet another question that i could not seems to find in the documents.

Currently, applying the above solution, we ALWAYS get the navigation entity with the parent entity. e.g. having fetchStrategy defined in Repository constructor, we ALWAYS get 'Company' when we query 'Approval'.  This doesnt really give us any control on when we want to include the navigation entities (company) and when not. 

Having used 'Include()' method, we had this control. Can you please advise how can we EXCLUDE the navigation entity (company) if we want to query for ONLY 'Approval' entity?

I hope I am able to convey my point to you! Telerik support had been great and still rocks, Thanks in advance
0
Ralph Waldenmaier
Telerik team
answered on 11 Jul 2014, 03:17 PM
Hi pomi,
Yes you are right. With the previous approach you are always getting it.
You can try to do the following.
public Approval GetById(object id, string sid)
{
    if (id == null)
    {
        throw new ArgumentNullException("id");
    }
    var oldFetchStrategy = service.FetchStrategy;
    Approval result = null;
    try
    {
        // define a fetch strategy for the current call only
        var newFetchStrategy = new Telerik.OpenAccess.FetchOptimization.FetchStrategy();
        newFetchStrategy.LoadWith<Approval>(a => a.Company);
        service.FetchStrategy = newFetchStrategy;
         
        result = service.GetAll().SingleOrDefault(i => i.ApprovalId == (long)id);  
     }
     finally
     {
        service.FetchStrategy = oldFetchStrategy;
     }
      
     return result;
}
Here I assume that you don't have modified the FetchPlan in the ctor of the ApprovalRepository class.
Instead here I am changing the default fetch plan for the current operation on the particular context. After the query is executed, the "old" FetchPlan is applied to the context again. A query that is fired after this will then no longer include the related Company object.

Hope this helps in your environment.
Do come back in case you need further assistance.

Regards,
Ralph Waldenmaier
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
0
pomi
Top achievements
Rank 1
answered on 11 Jul 2014, 06:37 PM
Hello Ralph

Thanks for your help, Yes, this seems to be a good workout in our environment, however, we have some problem. 

We are not able to access 'fetchStrategy' defined in 'OpenAccessBaseRepository' (code in my original question).

We are able to access 'fetchStrategy' in the 'ApprovalRepository' or 'CompanyRepository' which is derived from 'OpenAccessBaseRepository'. 

Even though in 'ApprovalService' constructor we declare 'this.service = new ApprovalRepository()' but still there is no 'service.fetchStrategy' !!!

I know there is something i am missing over here but I am just getting confused as to how to wrap my head around it.

Thanks for your continuous support, please can you give some insight!

Regards

0
Ralph Waldenmaier
Telerik team
answered on 15 Jul 2014, 07:25 AM
Hi pomi,
You can access the FetchStragegy by creating a new partial class for the generated OpenAccessBaseRepository and expose the FetchStrategy via a property.
See the following example:
public abstract partial class OpenAccessBaseRepository<TEntity, TContext> : IOpenAccessBaseRepository<TEntity, TContext>
        where TContext : OpenAccessContext, new()
    {
        public FetchStrategy FetchStrategy { get { return this.fetchStrategy; } set { this.fetchStrategy = value; } }
    }

Hope this helps.


Regards,
Ralph Waldenmaier
Telerik
 
OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
 
Tags
Getting Started
Asked by
pomi
Top achievements
Rank 1
Answers by
Boris Georgiev
Telerik team
pomi
Top achievements
Rank 1
Ralph Waldenmaier
Telerik team
Share this question
or