private static void MaterializeNavigationPropertiesObsolete <T>( dynamic mainEntity, dynamic projectedEntity, Type projectedEntityAnonymousType, ISelectPropertyBuilder <T> selectedSelectProperties) where T : class, IEntity { Type genericListType = typeof(List <>); var genericDynamicMapper = typeof(Mapper).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => m.Name == "DynamicMap").ToList()[2]; foreach (var projection in selectedSelectProperties.AllProjections.NavigationPropertiesProjections) { var navigationPropertyOnMainEntity = typeof(T).GetProperty(projection.ReferingPropertyName); var navigationPropertyOnProjectedAnonymousType = projectedEntityAnonymousType.GetProperty(projection.Name); var propertValues = (IEnumerable)navigationPropertyOnProjectedAnonymousType.GetValue(projectedEntity); Type listOfTypeProjectionType = genericListType.MakeGenericType(new[] { projection.Type }); var mapperOfProjectionType = genericDynamicMapper.MakeGenericMethod(projection.Type); IList navigationPropertyList = (IList)Activator.CreateInstance(listOfTypeProjectionType); foreach (var value in propertValues) { var valueOfNavigationPropertyProjection = mapperOfProjectionType.Invoke(null, new object[] { value }); navigationPropertyList.Add(valueOfNavigationPropertyProjection); } navigationPropertyOnMainEntity.SetValue(mainEntity, navigationPropertyList); } }
public T RetrieveByIdOld <T>(int id, ISelectPropertyBuilder <T> selectedSelectProperties) where T : class, IEntity { // The query will be projected onto an anonymous type. List <KeyValuePair <string, Type> > anonymousTypeProperties = new List <KeyValuePair <string, Type> >(); List <Expression> anonymousTypePropertiesValues = new List <Expression>(); ParameterExpression lambdaParameter = Expression.Parameter(typeof(T), "p"); foreach (var projection in selectedSelectProperties.AllProjections.BaseEntityProjections) { var projectionLambda = projection as LambdaExpression; MemberExpression member = CreateMemberExpression(projectionLambda); var propertyInfo = (PropertyInfo)member.Member; var propertyName = propertyInfo.Name; var propertyType = propertyInfo.PropertyType; var memberAccess = Expression.Property(lambdaParameter, propertyName); anonymousTypeProperties.Add(new KeyValuePair <string, Type>(propertyName, propertyType)); anonymousTypePropertiesValues.Add(memberAccess); } foreach (var navigationProperty in selectedSelectProperties.AllProjections.NavigationPropertiesProjections) { var navigationProperyType = navigationProperty.Type; // Creates the <T>.where(p => p.id == id) part of the expression MethodCallExpression whereCallExpression = CreateWhereCall <T>(id, navigationProperyType); ParameterExpression p1 = Expression.Parameter(navigationProperyType, "p1"); var navigationPropertyAnoymousTypeProperties = new List <KeyValuePair <string, Type> >(); List <MemberExpression> navigationPropertyAnoymousTypePropertiesValues = new List <MemberExpression>(); foreach (var projection in navigationProperty.Projections) { var navigationPropertyProjection = projection as LambdaExpression; MemberExpression member = CreateMemberExpression(navigationPropertyProjection); var propertyInfo = (PropertyInfo)member.Member; var propertyName = propertyInfo.Name; var propertyType = propertyInfo.PropertyType; var memberAccess = Expression.Property(p1, propertyName); navigationPropertyAnoymousTypeProperties.Add(new KeyValuePair <string, Type>(propertyName, propertyType)); navigationPropertyAnoymousTypePropertiesValues.Add(memberAccess); } var anonymousTypeOfNavigationPropertyProjection = AnonymousTypeUtils.CreateType(navigationPropertyAnoymousTypeProperties); Type typeOfSubProj = null; var anonymousTypeOfNavigationPropertyProjectionConstructor = anonymousTypeOfNavigationPropertyProjection .GetConstructor(navigationPropertyAnoymousTypeProperties.Select(kv => kv.Value).ToArray()); typeOfSubProj = anonymousTypeOfNavigationPropertyProjectionConstructor.ReflectedType; var selectMethod = typeof(Queryable).GetMethods().Where(m => m.Name == "Select").ToList()[0]; var genericSelectMethod = selectMethod.MakeGenericMethod(navigationProperyType, typeOfSubProj); var newInstanceOfTheGenericType = Expression.New(anonymousTypeOfNavigationPropertyProjectionConstructor, navigationPropertyAnoymousTypePropertiesValues); var projectionLamdba = Expression.Lambda(newInstanceOfTheGenericType, p1); MethodCallExpression selctCallExpression = Expression.Call( genericSelectMethod, whereCallExpression, projectionLamdba); var provider = ((IQueryable)context.Set <T>()).Provider; // TODO, Is it ok to assube navigation properties has the same provider? var theMethods = typeof(IQueryProvider).GetMethods(); var createQMethd = theMethods.Where(name => name.Name == "CreateQuery").ToList()[1]; var speciifMethod = createQMethd.MakeGenericMethod(anonymousTypeOfNavigationPropertyProjectionConstructor.ReflectedType); var navigationProppertyQueryWithProjection1 = speciifMethod.Invoke(provider, new object[] { selctCallExpression }); Type genericFunc = typeof(IEnumerable <>); Type funcOfTypeOfSubProj = genericFunc.MakeGenericType(typeOfSubProj); var allMethodsOnEnumerableClass = typeof(Enumerable).GetMethods(); var genericToListMethod = allMethodsOnEnumerableClass.Where(m => m.Name == "ToList").ToList()[0]; var toListOfTypeOfSubProj = genericToListMethod.MakeGenericMethod(typeOfSubProj); MethodCallExpression toListExpression11 = Expression.Call( toListOfTypeOfSubProj, Expression.Constant(navigationProppertyQueryWithProjection1)); anonymousTypeProperties.Add(new KeyValuePair <string, Type>(navigationProperty.Name, funcOfTypeOfSubProj)); anonymousTypePropertiesValues.Add(toListExpression11); } Type projectedEntityAnonymousType = AnonymousTypeUtils.CreateType(anonymousTypeProperties); var constructor = projectedEntityAnonymousType.GetConstructor(anonymousTypeProperties.Select(p => p.Value).ToArray()); var anonymousTypeInstance = Expression.New(constructor, anonymousTypePropertiesValues); Expression <Func <T, dynamic> > lambd11a1 = Expression.Lambda <Func <T, dynamic> >(anonymousTypeInstance, lambdaParameter); var projectedEntity = context.Set <T>() .AsNoTracking() .Where(e => e.Id == id) .Select(lambd11a1) .Single(); var mainEntity = Mapper.DynamicMap <T>(projectedEntity); mainEntity.Id = id; if (selectedSelectProperties.AllProjections.NavigationPropertiesProjections.Count() > 0) { MaterializeNavigationPropertiesObsolete <T>(mainEntity, projectedEntity, projectedEntityAnonymousType, selectedSelectProperties); } var alreadytrackedentity = context.ChangeTracker.Entries <T>().Where(e => e.Entity.Id == id).SingleOrDefault(); if (alreadytrackedentity != null) { // Remove it from tracking alreadytrackedentity.State = EntityState.Detached; } context.Attach(mainEntity); return(mainEntity); }
public void CanRetrieveByIdUsingTheBuildingQueryCache() { #region Arrange var blog = new Blog(); blog.Name = Fixture.Create <string>(); var post = new Post(); post.Text = Fixture.Create <string>(); post.Url = Guid.NewGuid().ToString(); blog.Posts.AddRange(new List <Post>() { post }); using (var uow = UoWFactory.Create()) { var repository = uow.Create(); var createdPost = repository.Add(blog); uow.Commit(); } #endregion Arrange #region Act long first; long second; using (var uow = UoWFactory.Create()) { var repository = uow.Create(); Stopwatch stopwatch = Stopwatch.StartNew(); ISelectPropertyBuilder <Blog> builder = repository.PropertySelectBuilder <Blog>(blog); var pp = builder .Select(p => p.Name) .Include <Post>(m => m.Posts, p => p.Date, p => p.Text) .Build(); stopwatch.Stop(); first = stopwatch.ElapsedMilliseconds; var retrievedBlogWithPosts = repository.RetrieveById(blog.Id, pp); } using (var uow = UoWFactory.Create()) { var repository = uow.Create(); Stopwatch stopwatch = Stopwatch.StartNew(); ISelectPropertyBuilder <Blog> builder = repository .PropertySelectBuilder <Blog>(blog); var pp = builder .Select(p => p.Name) .Include <Post>(m => m.Posts, p => p.Date, p => p.Text) .Build(); second = stopwatch.ElapsedMilliseconds; var retrievedBlogWithPosts = repository.RetrieveById(blog.Id, pp); } #endregion Act #region Assert // Assert the latter is faster! #endregion Assert }