1

I am trying to replace the joins and use include but I don't know how to do that:

          IRepository<Call> callRepository =
            ObjectFactory.GetInstance<IRepository<Call>>();

        IRepository<Reason> reasonRepository =
            ObjectFactory.GetInstance<IRepository<Reason>>();

        IRepository<SimTask.Domain.Business.Entities.System.Company>
            companyRepository = ObjectFactory.GetInstance<IRepository<SimTask.Domain.
            Business.Entities.System.Company>>();

        IQueryable<CallsListItem> x =
            from call in callRepository.GetQuery()
            join reason in reasonRepository.GetQuery() on call.ReasonId equals reason.Id
            join company in companyRepository.GetQuery() on call.CompanyId equals company.CompanyId
            where call.CompanyId == companyId &&
                (!isClosed.HasValue || call.IsClosed.Equals(isClosed.Value))
            select new CallsListItem()
            {
                CallId = call.Id,
                Description = call.Description,
                CloseDateTime = call.CloseDateTime,
                IsClosed = call.IsClosed,
                OpenDateTime = call.OpenDateTime,
                PhoneNumber = call.PhoneNumber,
                ReasonName = reason.Name,
                CompanyName = company.CompanyName
            };

IRepository is implemented by:

public class EFRepository<T> : IRepository<T> where T : class
    {
        ObjectContext _context;
        IObjectSet<T> _objectSet;

        private ObjectContext Context
        {
            get
            {
                if (_context == null)
                {
                    _context = GetCurrentUnitOfWork<EFUnitOfWork>().Context;
                }
                return _context;
            }
        }

        private IObjectSet<T> ObjectSet
        {
            get
            {
                if (_objectSet == null)
                {
                    _objectSet = this.Context.CreateObjectSet<T>();
                }
                return _objectSet;
            }
        }

        public TUnitOfWork GetCurrentUnitOfWork<TUnitOfWork>() where TUnitOfWork : IUnitOfWork
        {
            return (TUnitOfWork)UnitOfWork.Current;
        }

        public IQueryable<T> GetQuery()
        {
            return ObjectSet;
        }

        public IEnumerable<T> GetAll()
        {
            return GetQuery().ToList();
        }

        public IEnumerable<T> Find(Func<T,bool> where)
        {
            return this.ObjectSet.Where<T>(where);
        }

        public T  Single(Func<T,bool> where)
        {
            return this.ObjectSet.Single<T>(where);
        }

        public T First(Func<T,bool> where)
        {
            return this.ObjectSet.First<T>(where);
        }

        public void Delete(T entity)
        {
            this.ObjectSet.DeleteObject(entity);
        }

        public void Add(T entity)
        {
            this.ObjectSet.AddObject(entity);
        }

        public void Attach(T entity)
        {
            this.ObjectSet.Attach(entity);
        }

        public void SaveChanges()
        {
            this.Context.SaveChanges();
        }
    }

Why is Include better then joins?
How can I do Include?

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
Naor
  • 23,465
  • 48
  • 152
  • 268

1 Answers1

2

Include is eager loading and it fills navigation properties in real entities without need to project to non entity type - this cannot be achieved with joins. Also Include uses left outer joins whereas your query uses inner joins so you will not get entities which don't have related entity.

In EFv1 and EFv4 Include is a method of ObjectQuery. I wrote this answer using EFv4.1 which contains extension method for IQueryable<T> as well as Includes with lambda expression. You can try it - it is just another library you will link to your project and you can still use EFv4.

The reason to wrap Include in custom method is not introducing dependency to EF in upper layer. If you don't download EFv4.1 you can use this:

public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params string[] includes)
    where T : class
{
    if (includes != null)
    {
        var objectQuery = query as ObjectQuery;

        if (objectQuery == null)
        {
            throw new InvalidOperationException("...");
        }

        objectQuery = includes.Aggregate(objectQuery, 
                  (current, include) => current.Include(include));
    }

    return objectQuery;
}

The big disadvantage in both approaches (EFv4 and EFv4.1) is casting to ObjectQuery (EFv4.1 do it internally) - this can be serious issue in unit tests where you don't work with real queries.

Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Hi, I didn't understand this: "The reason to wrap Include in custom method is not introducing dependency to EF in upper layer". By using this I force the use of EF4.1. Moreover - I put this extenstion in the data layer of my solution.. – Naor Apr 21 '11 at 21:47
  • Yes but if want to hide all EF related code in your data layer you don't want to expose Include from entity framework to upper layer, because of that you can wrap it into custom method in you data layer. – Ladislav Mrnka Apr 21 '11 at 22:00
  • wow.. that leads to other question.. I make queries that relates to business entities in my business layer so I need this include.. Moreover, in order to initialize my application - the presentation layer should know the data layer (there is initialization of ObjectFactory of StructureMap in the global.asax) – Naor Apr 21 '11 at 22:18
  • @Naor: Yes you need the dependency on EF if you bootstrap StructureMap from the code. – Ladislav Mrnka Apr 22 '11 at 07:16