private static Expression AssignReferenceNavigation(
     ParameterExpression entity,
     ParameterExpression relatedEntity,
     INavigationBase navigation)
 {
     return(entity.MakeMemberAccess(navigation.GetMemberInfo(forMaterialization: true, forSet: true)).Assign(relatedEntity));
 }
Ejemplo n.º 2
0
        private static IClrCollectionAccessor CreateGeneric <TEntity, TCollection, TElement>(INavigationBase navigation)
            where TEntity : class
            where TCollection : class, IEnumerable <TElement>
            where TElement : class
        {
            var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
            var valueParameter  = Expression.Parameter(typeof(TCollection), "collection");

            var memberInfoForRead = navigation.GetMemberInfo(forMaterialization: false, forSet: false);

            navigation.TryGetMemberInfo(forConstruction: false, forSet: true, out var memberInfoForWrite, out _);
            navigation.TryGetMemberInfo(forConstruction: true, forSet: true, out var memberInfoForMaterialization, out _);

            var memberAccessForRead = (Expression)Expression.MakeMemberAccess(entityParameter, memberInfoForRead);

            if (memberAccessForRead.Type != typeof(TCollection))
            {
                memberAccessForRead = Expression.Convert(memberAccessForRead, typeof(TCollection));
            }

            var getterDelegate = Expression.Lambda <Func <TEntity, TCollection> >(
                memberAccessForRead,
                entityParameter).Compile();

            Action <TEntity, TCollection>?setterDelegate = null;
            Action <TEntity, TCollection>?setterDelegateForMaterialization = null;
            Func <TEntity, Action <TEntity, TCollection>, TCollection>?createAndSetDelegate = null;
            Func <TCollection>?createDelegate = null;

            if (memberInfoForWrite != null)
            {
                setterDelegate = CreateSetterDelegate(entityParameter, memberInfoForWrite, valueParameter);
            }

            if (memberInfoForMaterialization != null)
            {
                setterDelegateForMaterialization = CreateSetterDelegate(entityParameter, memberInfoForMaterialization, valueParameter);
            }

            var concreteType = new CollectionTypeFactory().TryFindTypeToInstantiate(
                typeof(TEntity),
                typeof(TCollection),
                navigation.DeclaringEntityType.Model[CoreAnnotationNames.FullChangeTrackingNotificationsRequiredAnnotation] != null);

            if (concreteType != null)
            {
                var isHashSet = concreteType.IsGenericType && concreteType.GetGenericTypeDefinition() == typeof(HashSet <>);
                if (setterDelegate != null ||
                    setterDelegateForMaterialization != null)
                {
                    if (isHashSet)
                    {
                        createAndSetDelegate = (Func <TEntity, Action <TEntity, TCollection>, TCollection>)_createAndSetHashSet
                                               .MakeGenericMethod(typeof(TEntity), typeof(TCollection), typeof(TElement))
                                               .CreateDelegate(typeof(Func <TEntity, Action <TEntity, TCollection>, TCollection>));
                    }
                    else if (IsObservableHashSet(concreteType))
                    {
                        createAndSetDelegate = (Func <TEntity, Action <TEntity, TCollection>, TCollection>)_createAndSetObservableHashSet
                                               .MakeGenericMethod(typeof(TEntity), typeof(TCollection), typeof(TElement))
                                               .CreateDelegate(typeof(Func <TEntity, Action <TEntity, TCollection>, TCollection>));
                    }
                    else
                    {
                        createAndSetDelegate = (Func <TEntity, Action <TEntity, TCollection>, TCollection>)_createAndSet
                                               .MakeGenericMethod(typeof(TEntity), typeof(TCollection), concreteType)
                                               .CreateDelegate(typeof(Func <TEntity, Action <TEntity, TCollection>, TCollection>));
                    }
                }

                if (isHashSet)
                {
                    createDelegate = (Func <TCollection>)_createHashSet
                                     .MakeGenericMethod(typeof(TCollection), typeof(TElement))
                                     .CreateDelegate(typeof(Func <TCollection>));
                }
                else if (IsObservableHashSet(concreteType))
                {
                    createDelegate = (Func <TCollection>)_createObservableHashSet
                                     .MakeGenericMethod(typeof(TCollection), typeof(TElement))
                                     .CreateDelegate(typeof(Func <TCollection>));
                }
                else
                {
                    createDelegate = (Func <TCollection>)_create
                                     .MakeGenericMethod(typeof(TCollection), concreteType)
                                     .CreateDelegate(typeof(Func <TCollection>));
                }
            }

            return(new ClrICollectionAccessor <TEntity, TCollection, TElement>(
                       navigation.Name,
                       getterDelegate,
                       setterDelegate,
                       setterDelegateForMaterialization,
                       createAndSetDelegate,
                       createDelegate));