public async Task TestAsRequested()
        {
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() =>
            {
                IDataModelCollection <Model.SharePoint.IList> bla = null;
                var a = bla.AsRequested();
            });

#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        }
        /// <summary>
        /// Returns an <see cref="IEnumerable{T}" /> which can be enumerated without executing an actual LINQ query on the target data provider.
        /// </summary>
        /// <typeparam name="TSource"> The type of the elements of <paramref name="source" />. </typeparam>
        /// <param name="source"> An <see cref="IDataModelCollection{T}" /> to enumerate. </param>
        /// <returns> The query results. </returns>
        /// <exception cref="InvalidOperationException"> <paramref name="source" /> is <see langword="null" />. </exception>
        /// <exception cref="ArgumentNullException"> <paramref name="source" /> is not a <see cref="IAsyncEnumerable{T}" />. </exception>
        public static IEnumerable <TSource> AsRequested <TSource>(
            this IDataModelCollection <TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (source is BaseQueryableDataModelCollection <TSource> enumerable)
            {
                return((IEnumerable <TSource>)enumerable.RequestedItems);
            }

            throw new InvalidOperationException(PnPCoreResources.Exception_InvalidOperation_NotAsyncQueryableSource);
        }
Beispiel #3
0
        /// <summary>
        /// When implemented, loads the full object graph for the first
        /// <see cref="DataModel"/> that is returned from the specified
        /// <paramref name="query"/>, within the specified database
        /// <paramref name="transactionContext"/>.
        /// </summary>
        /// <param name="query"></param>
        /// <param name="transactionContext"></param>
        /// <param name="depth"></param>
        /// <param name="loadedModels">
        /// Used for keeping recursive loading from resulting
        /// in infinite loops. Evaluate each loaded item from
        /// a database result set against this collection; if
        /// there is a match, use the collection item,
        /// otherwise use the database loaded item, deep-load
        /// it, and add it to this collection.
        /// </param>
        /// <returns></returns>
        public virtual TModel DeepLoadModel <TModel>(
            DataModelQuery <TModel> query, int?depth, DbTransaction transactionContext,
            List <DataModel> loadedModels
            ) where TModel : DataModel
        {
            TModel e = LoadModel(query, transactionContext);

            if (e == null)
            {
                return(e);
            }
            if (loadedModels == null)
            {
                loadedModels = new List <DataModel>();
            }
            if (loadedModels.Contains(e))
            {
                return((TModel)loadedModels[loadedModels.IndexOf(e)]);
            }
            foreach (DataModel previouslyLoadedModel in loadedModels)
            {
                if (query.GetType().IsGenericType)
                {
                    Type qt = query.GetType().GetGenericArguments()[0];
                    if (previouslyLoadedModel.GetType().IsOrInherits(qt) &&
                        previouslyLoadedModel.Equals(e) &&
                        previouslyLoadedModel is TModel)
                    {
                        return((TModel)previouslyLoadedModel);
                    }
                }
            }
            if (!loadedModels.Contains(e))
            {
                loadedModels.Add(e);
            }
            foreach (var fe_kvp in e.EntityMappings.ForeignModelMappings)
            {
                if (depth == null || depth > 0)
                {
                    ForeignDataModelAttribute fe = fe_kvp.Value;
                    Type targetEntityType        = fe.TargetMemberType;
                    while (targetEntityType.IsGenericType &&
                           targetEntityType.IsOrInherits(typeof(IEnumerable)))
                    {
                        targetEntityType = targetEntityType.GetGenericArguments().Last();
                    }
                    if (!targetEntityType.IsDataModel())
                    {
                        targetEntityType = typeof(DataModel <>).MakeGenericType(targetEntityType);
                    }
                    Type subQueryType = typeof(DataModelQuery <>).MakeGenericType(targetEntityType);

                    Relationship relationship = fe.Relationship;
                    if (relationship == Relationship.ManyToMany &&
                        string.IsNullOrEmpty(fe.MappingTable))
                    {
                        relationship = Relationship.OneToMany;
                    }
                    switch (relationship)
                    {
                    case Relationship.OneToOne:
                    case Relationship.ManyToOne:
                        IDataModelQuery subQuery = ((IDataModelQuery)Activator.CreateInstance(subQueryType))
                                                   .WhereColumn[fe.RelatedTableColumn].IsEqualTo(
                            e.ColumnMappedValue[fe.LocalColumn]);

                        DataModel e2 = DeepLoadModel(targetEntityType, subQuery,
                                                     depth == null ? null : depth - 1,
                                                     transactionContext, loadedModels);
                        object e2o = e2;
                        if (!fe.TargetMemberType.IsDataModel())
                        {
                            e2o = (e2).Entity;
                        }
                        if (fe.TargetMember.MemberType == MemberTypes.Field)
                        {
                            ((FieldInfo)fe.TargetMember).SetValue(e.Entity, e2o);
                        }
                        else if (fe.TargetMember.MemberType == MemberTypes.Property)
                        {
                            ((PropertyInfo)fe.TargetMember).SetValue(e.Entity, e2o, new object[] {});
                        }
                        break;

                    case Relationship.OneToMany:
                        IDataModelQuery subQuery2 = ((IDataModelQuery)Activator.CreateInstance(subQueryType))
                                                    .WhereColumn[fe.RelatedTableColumn].IsEqualTo(
                            e.ColumnMappedValue[fe.LocalColumn]);

                        IDataModelCollection e2c = DeepLoadModels(targetEntityType, subQuery2, depth,
                                                                  transactionContext, loadedModels);
                        object e2ct = Activator.CreateInstance(fe.TargetMemberType);
                        if (e2ct is IList)
                        {
                            bool de = fe.TargetMemberType.IsGenericType &&
                                      fe.TargetMemberType.GetGenericArguments().Last().IsDataModel();
                            foreach (object e2cx in e2c)
                            {
                                if (de)
                                {
                                    ((IList)e2ct).Add(e2cx);
                                }
                                else
                                {
                                    object e2cx2 = ((DataModel)e2cx).Entity;
                                    ((IList)e2ct).Add(e2cx2);
                                }
                            }
                        }
                        else
                        {
                            e2ct = ((IList)e2c)[0];
                        }
                        if (fe.TargetMember.MemberType == MemberTypes.Field)
                        {
                            ((FieldInfo)fe.TargetMember).SetValue(e.Entity, e2ct);
                        }
                        else if (fe.TargetMember.MemberType == MemberTypes.Property)
                        {
                            ((PropertyInfo)fe.TargetMember).SetValue(e.Entity, e2ct, new object[] {});
                        }
                        break;

                    case Relationship.ManyToMany:
                        if (!fe.TargetMemberType.IsOrInherits(typeof(IList)))
                        {
                            throw new InvalidCastException(
                                      "Cannot apply ManyToMany binding to a non-IList property.");
                        }
                        Type tleft       = fe.DeclaringType;
                        Type tleftEntity = tleft;
                        while (tleftEntity.IsDataModelWrapper(true))
                        {
                            if (tleftEntity.BaseType != (typeof(DataModel <>)).BaseType)
                            {
                                tleftEntity = tleftEntity.BaseType;
                            }
                            else
                            {
                                tleftEntity = tleftEntity.GetGenericArguments()[0];
                            }
                        }
                        Type tright = (fe.TargetMemberType.IsGenericType &&
                                       !fe.TargetMemberType.IsDataModel() &&
                                       fe.TargetMemberType.IsOrInherits(typeof(IList)))
                                              ? fe.TargetMemberType.GetGenericArguments()[0]
                                              :
                                      fe.TargetMemberType;
                        Type trightEntity = tright;
                        if (!tright.IsDataModel())
                        {
                            tright = typeof(DataModel <>).MakeGenericType(tright);
                        }
                        Type mapType = typeof(DataModelMap.RuntimeMappingTable <,>)
                                       .MakeGenericType(
                            // left side of mapping table
                            fe.TargetMember.DeclaringType,
                            // right side
                            tright);
                        var mapObj = (DataModel)Activator.CreateInstance(mapType);
                        mapObj.EntityMappings.TableMapping.Schema = fe.MappingTableSchema ??
                                                                    ProviderDefaults.DefaultSchema;
                        mapObj.EntityMappings.TableMapping.Table = fe.MappingTable ??
                                                                   (string.Compare(trightEntity.Name,
                                                                                   tleftEntity.Name) == -1
                                                                            ? trightEntity.Name +
                                                                    tleftEntity.Name
                                                                            : tleftEntity.Name +
                                                                    trightEntity.Name);
                        DataModelColumnAttribute mapLeftCol = mapObj.EntityMappings.FieldMappings["LeftColumn"];
                        mapLeftCol.ColumnName = fe.LocalColumn;
                        mapLeftCol.DbType     = e.EntityMappings
                                                .GetFieldMappingByDbColumnName(fe.LocalColumn).DbType;
                        mapLeftCol.TargetMemberType = e.EntityMappings
                                                      .GetFieldMappingByDbColumnName(fe.LocalColumn).TargetMemberType;

                        Type mapQueryType = typeof(DataModelQuery <>).MakeGenericType(new[] { mapType });
                        var  mapQuery     = (IDataModelQuery)Activator.CreateInstance(mapQueryType);
                        mapQuery.WhereColumn[fe.LocalColumn].IsEqualTo(
                            e.ColumnMappedValue[fe.LocalColumn]);


                        IDataModelCollection mapdes = LoadModels(mapType, mapQuery, transactionContext);

                        var mappedDEs = new DataModelCollection <DataModel>();
                        foreach (DataModel de in mapdes)     // de is a MappingTable<L,R>
                        {
                            var mappedDEQuery = (IDataModelQuery)
                                                Activator.CreateInstance(typeof(DataModelQuery <>)
                                                                         .MakeGenericType(targetEntityType));
                            mappedDEQuery.WhereColumn[fe.RelatedTableColumn]
                            .IsEqualTo(de.ColumnMappedValue[fe.RelatedTableColumn]);

                            DataModel mappedDE = DeepLoadModel(targetEntityType, mappedDEQuery,
                                                               depth == null ? null : depth - 1,
                                                               transactionContext, loadedModels);

                            if (mappedDE != null)
                            {
                                mappedDEs.Add(mappedDE);
                            }
                        }

                        Type mmtargtype = fe.TargetMemberType;
                        var  mmtargcol  = (IList)Activator.CreateInstance(fe.TargetMemberType);
                        Type mapdeType  = null;
                        foreach (DataModel mapde in mappedDEs)
                        {
                            if (mapdeType == null)
                            {
                                mapdeType = mapde.GetType();
                            }
                            object deinst = mapde;
                            if (mmtargtype.IsGenericType &&
                                !mmtargtype.GetGenericArguments()[0].IsDataModel())
                            {
                                deinst = mapde.Entity;
                            }
                            mmtargcol.Add(deinst);
                        }
                        if (fe.TargetMember is FieldInfo)
                        {
                            ((FieldInfo)fe.TargetMember).SetValue(e, mmtargcol);
                        }
                        else if (fe.TargetMember is PropertyInfo)
                        {
                            ((PropertyInfo)fe.TargetMember).SetValue(
                                e.Entity, mmtargcol, new object[] {});
                        }
                        break;
                    }
                }
            }
            foreach (var field_kvp in e.EntityMappings.FieldMappings)
            {
                DataModelColumnAttribute field = field_kvp.Value;
                if (field.IsForeignKey &&
                    field.ForeignKeyMapping.AssignToMember != null)
                {
                    LoadMember(e, field, field_kvp.Key, transactionContext, loadedModels);
                }
            }
            return(e);
        }