public CachedTableConstructor(CachedTableBase cachedTable, AliasGenerator?aliasGenerator)
        {
            this.cachedTable = cachedTable;
            this.table       = cachedTable.Table;

            if (aliasGenerator != null)
            {
                this.aliasGenerator = aliasGenerator;
                this.currentAlias   = aliasGenerator.NextTableAlias(table.Name.Name);
            }

            this.tupleType = TupleReflection.TupleChainType(table.Columns.Values.Select(GetColumnType));

            this.origin = Expression.Parameter(tupleType, "origin");
        }
Example #2
0
        public SemiCachedController(CachedTableBase cachedTable)
        {
            this.cachedTable = cachedTable;

            CacheLogic.semiControllers.GetOrCreate(typeof(T)).Add(cachedTable);

            var ee = Schema.Current.EntityEvents <T>();

            ee.Saving += ident =>
            {
                if (ident.IsGraphModified && !ident.IsNew)
                {
                    cachedTable.LoadAll();

                    if (cachedTable.Contains(ident.Id))
                    {
                        DisableAndInvalidate();
                    }
                }
            };
            //ee.PreUnsafeDelete += query => DisableAndInvalidate();
            ee.PreUnsafeUpdate += (update, entityQuery) => DisableAndInvalidateMassive();
            ee.PreUnsafeInsert += (query, constructor, entityQuery) =>
            {
                if (constructor.Body.Type.IsInstantiationOf(typeof(MListElement <,>)))
                {
                    DisableAndInvalidateMassive();
                }

                return(constructor);
            };
            ee.PreUnsafeMListDelete += (mlistQuery, entityQuery) => DisableAndInvalidateMassive();
            ee.PreBulkInsert        += inMListTable =>
            {
                if (inMListTable)
                {
                    DisableAndInvalidateMassive();
                }
            };
        }
        private Expression GetEntity(bool isLite, IColumn column, Type type)
        {
            Expression id = GetTupleProperty(column);

            if (isLite)
            {
                Expression lite;
                switch (CacheLogic.GetCacheType(type))
                {
                case CacheType.Cached:
                {
                    lite = Expression.Call(retriever, miRequestLite.MakeGenericMethod(type),
                                           Lite.NewExpression(type, NewPrimaryKey(id.UnNullify()), Expression.Constant(null, typeof(string))));

                    lite = Expression.Call(retriever, miModifiablePostRetrieving.MakeGenericMethod(typeof(LiteImp)), lite.TryConvert(typeof(LiteImp))).TryConvert(lite.Type);

                    break;
                }

                case CacheType.Semi:
                {
                    string lastPartialJoin = CreatePartialInnerJoin(column);

                    CachedTableBase ctb = ciCachedSemiTable.GetInvoker(type)(cachedTable.controller, aliasGenerator !, lastPartialJoin, remainingJoins);

                    if (cachedTable.subTables == null)
                    {
                        cachedTable.subTables = new List <CachedTableBase>();
                    }

                    cachedTable.subTables.Add(ctb);

                    ctb.ParentColumn = column;

                    lite = Expression.Call(Expression.Constant(ctb), ctb.GetType().GetMethod("GetLite"), NewPrimaryKey(id.UnNullify()), retriever);

                    break;
                }

                default: throw new InvalidOperationException("{0} should be cached at this stage".FormatWith(type));
                }

                if (!id.Type.IsNullable())
                {
                    return(lite);
                }

                return(Expression.Condition(Expression.Equal(id, NullId), Expression.Constant(null, Lite.Generate(type)), lite));
            }
            else
            {
                switch (CacheLogic.GetCacheType(type))
                {
                case CacheType.Cached: return(Expression.Call(retriever, miRequest.MakeGenericMethod(type), WrapPrimaryKey(id.Nullify())));

                case CacheType.Semi:
                {
                    string lastPartialJoin = CreatePartialInnerJoin(column);

                    CachedTableBase ctb = ciCachedTable.GetInvoker(type)(cachedTable.controller, aliasGenerator, lastPartialJoin, remainingJoins);

                    if (cachedTable.subTables == null)
                    {
                        cachedTable.subTables = new List <CachedTableBase>();
                    }

                    cachedTable.subTables.Add(ctb);

                    ctb.ParentColumn = column;

                    var entity = Expression.Parameter(type);
                    LambdaExpression lambda = Expression.Lambda(typeof(Action <>).MakeGenericType(type),
                                                                Expression.Call(Expression.Constant(ctb), ctb.GetType().GetMethod("Complete"), entity, retriever),
                                                                entity);

                    return(Expression.Call(retriever, miComplete.MakeGenericMethod(type), WrapPrimaryKey(id.Nullify()), lambda));
                }

                default: throw new InvalidOperationException("{0} should be cached at this stage".FormatWith(type));
                }
            }
        }
        public Expression MaterializeField(Field field)
        {
            if (field is FieldValue)
            {
                var value = GetTupleProperty((IColumn)field);
                return(value.Type == field.FieldType ? value : Expression.Convert(value, field.FieldType));
            }

            if (field is FieldEnum)
            {
                return(Expression.Convert(GetTupleProperty((IColumn)field), field.FieldType));
            }

            if (field is IFieldReference)
            {
                var  nullRef = Expression.Constant(null, field.FieldType);
                bool isLite  = ((IFieldReference)field).IsLite;

                if (field is FieldReference)
                {
                    IColumn column = (IColumn)field;

                    return(GetEntity(isLite, column, field.FieldType.CleanType()));
                }

                if (field is FieldImplementedBy ib)
                {
                    var call = ib.ImplementationColumns.Aggregate((Expression)nullRef, (acum, kvp) =>
                    {
                        IColumn column = (IColumn)kvp.Value;

                        Expression entity = GetEntity(isLite, column, kvp.Key);

                        return(Expression.Condition(Expression.NotEqual(WrapPrimaryKey(GetTupleProperty(column)), NullId),
                                                    Expression.Convert(entity, field.FieldType),
                                                    acum));
                    });

                    return(call);
                }

                if (field is FieldImplementedByAll iba)
                {
                    Expression id     = GetTupleProperty(iba.Column);
                    Expression typeId = GetTupleProperty(iba.ColumnType);

                    if (isLite)
                    {
                        var liteCreate = Expression.Call(miGetIBALite.MakeGenericMethod(field.FieldType.CleanType()),
                                                         Expression.Constant(Schema.Current),
                                                         NewPrimaryKey(typeId.UnNullify()),
                                                         id.UnNullify());

                        var liteRequest = Expression.Call(retriever, miRequestLite.MakeGenericMethod(Lite.Extract(field.FieldType) !), liteCreate);

                        return(Expression.Condition(Expression.NotEqual(WrapPrimaryKey(id), NullId), liteRequest, nullRef));
                    }
                    else
                    {
                        return(Expression.Call(retriever, miRequestIBA.MakeGenericMethod(field.FieldType), typeId, id));
                    }
                }
            }

            if (field is FieldEmbedded fe)
            {
                Expression ctor = Expression.MemberInit(Expression.New(fe.FieldType),
                                                        fe.EmbeddedFields.Values.Select(f => Expression.Bind(f.FieldInfo, MaterializeField(f.Field))));

                var result = Expression.Call(retriever, miModifiablePostRetrieving.MakeGenericMethod(ctor.Type), ctor);

                if (fe.HasValue == null)
                {
                    return(result);
                }

                return(Expression.Condition(
                           Expression.Equal(GetTupleProperty(fe.HasValue), Expression.Constant(true)),
                           result,
                           Expression.Constant(null, field.FieldType)));
            }


            if (field is FieldMList mListField)
            {
                var idColumn = table.Columns.Values.OfType <FieldPrimaryKey>().First();

                string lastPartialJoin = CreatePartialInnerJoin(idColumn);

                Type elementType = field.FieldType.ElementType() !;

                CachedTableBase ctb = ciCachedTableMList.GetInvoker(elementType)(cachedTable.controller, mListField.TableMList, aliasGenerator, lastPartialJoin, remainingJoins);

                if (cachedTable.subTables == null)
                {
                    cachedTable.subTables = new List <CachedTableBase>();
                }

                cachedTable.subTables.Add(ctb);

                return(Expression.Call(Expression.Constant(ctb), ctb.GetType().GetMethod("GetMList"), NewPrimaryKey(GetTupleProperty(idColumn)), retriever));
            }

            throw new InvalidOperationException("Unexpected {0}".FormatWith(field.GetType().Name));
        }