Beispiel #1
0
        void DisableAndInvalidate()
        {
            CacheLogic.DisableAllConnectedTypesInTransaction(this.cachedTable.controller.Type);

            Transaction.PostRealCommit -= Transaction_PostRealCommit;
            Transaction.PostRealCommit += Transaction_PostRealCommit;
        }
Beispiel #2
0
            public override void AttachInvalidations(SchemaBuilder sb, InvalidateWith invalidateWith, EventHandler invalidate)
            {
                if (CacheLogic.GloballyDisabled)
                {
                    base.AttachInvalidations(sb, invalidateWith, invalidate);
                }
                else
                {
                    EventHandler <CacheEventArgs> onInvalidation = (sender, args) =>
                    {
                        if (args == CacheEventArgs.Invalidated)
                        {
                            invalidate(sender, args);
                        }
                        else if (args == CacheEventArgs.Disabled)
                        {
                            if (Transaction.InTestTransaction)
                            {
                                invalidate(sender, args);
                                Transaction.Rolledback += dic => invalidate(sender, args);
                            }

                            Transaction.PostRealCommit += dic => invalidate(sender, args);
                        }
                    };

                    foreach (var t in invalidateWith.Types)
                    {
                        CacheLogic.TryCacheTable(sb, t);

                        GetController(t).Invalidated += onInvalidation;
                    }
                }
            }
Beispiel #3
0
 void DisableAndInvalidateMassive()
 {
     if (CacheLogic.IsAssumedMassiveChangeAsInvalidation <T>())
     {
         DisableAndInvalidate();
     }
 }
Beispiel #4
0
        static Color GetColor(Type type, Func <Type, bool> cacheHint)
        {
            if (type.IsEnumEntityOrSymbol())
            {
                return(Color.Red);
            }

            switch (CacheLogic.GetCacheType(type))
            {
            case CacheType.Cached: return(Color.Purple);

            case CacheType.Semi: return(Color.Pink);
            }

            if (typeof(Symbol).IsAssignableFrom(type))
            {
                return(Color.Orange);
            }

            if (cacheHint != null && cacheHint(type))
            {
                return(Color.Yellow);
            }

            return(Color.Green);
        }
Beispiel #5
0
        private Expression GetEntity(bool isLite, IColumn column, Type entityType, CachedTableConstructor constructor)
        {
            Expression id = constructor.GetTupleProperty(column);

            var pk = CachedTableConstructor.WrapPrimaryKey(id);

            CachedTableConstructor typeConstructor = CacheLogic.GetCacheType(entityType) == CacheType.Cached ?
                                                     CacheLogic.GetCachedTable(entityType).Constructor :
                                                     constructor.cachedTable.SubTables !.SingleEx(a => a.ParentColumn == column).Constructor;

            return(new CachedEntityExpression(pk, entityType, typeConstructor, null !));
        }
        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));
                }
            }
        }
Beispiel #7
0
 void Transaction_PostRealCommit(Dictionary <string, object> obj)
 {
     cachedTable.ResetAll(forceReset: false);
     CacheLogic.NotifyInvalidateAllConnectedTypes(this.cachedTable.controller.Type);
 }
Beispiel #8
0
        public override void SchemaCompleted()
        {
            List <IColumn> columns = new List <IColumn> {
                table.PrimaryKey
            };

            ParameterExpression reader = Expression.Parameter(typeof(FieldReader));

            var expression = ToStringExpressionVisitor.GetToString(table, reader, columns);

            //Query
            using (ObjectName.OverrideOptions(new ObjectNameOptions {
                AvoidDatabaseName = true
            }))
            {
                string select = "SELECT {0}\r\nFROM {1} {2}\r\n".FormatWith(
                    columns.ToString(c => currentAlias + "." + c.Name.SqlEscape(), ", "),
                    table.Name.ToString(),
                    currentAlias.ToString());

                select += this.lastPartialJoin + currentAlias + "." + table.PrimaryKey.Name.SqlEscape() + "\r\n" + this.remainingJoins;

                query = new SqlPreCommandSimple(select);
            }

            //Reader
            {
                var kvpConstructor = Expression.New(CachedTableConstructor.ciKVPIntString,
                                                    CachedTableConstructor.NewPrimaryKey(FieldReader.GetExpression(reader, 0, this.table.PrimaryKey.Type)),
                                                    expression);

                rowReader = Expression.Lambda <Func <FieldReader, KeyValuePair <PrimaryKey, string> > >(kvpConstructor, reader).Compile();
            }

            toStrings = new ResetLazy <Dictionary <PrimaryKey, string> >(() =>
            {
                CacheLogic.AssertSqlDependencyStarted();

                var connector = (SqlConnector)Connector.Current;

                var subConnector = connector.ForDatabase(table.Name.Schema?.Database);

                Dictionary <PrimaryKey, string> result = new Dictionary <PrimaryKey, string>();

                using (MeasureLoad())
                    using (Connector.Override(subConnector))
                        using (Transaction tr = Transaction.ForceNew(IsolationLevel.ReadCommitted))
                        {
                            if (CacheLogic.LogWriter != null)
                            {
                                CacheLogic.LogWriter.WriteLine("Load {0}".FormatWith(GetType().TypeName()));
                            }

                            ((SqlConnector)Connector.Current).ExecuteDataReaderOptionalDependency(query, OnChange, fr =>
                            {
                                var kvp         = rowReader(fr);
                                result[kvp.Key] = kvp.Value;
                            });
                            tr.Commit();
                        }

                return(result);
            }, mode: LazyThreadSafetyMode.ExecutionAndPublication);

            if (this.subTables != null)
            {
                foreach (var item in this.subTables)
                {
                    item.SchemaCompleted();
                }
            }
        }
Beispiel #9
0
        public CachedTableMList(ICacheLogicController controller, TableMList table, AliasGenerator aliasGenerator, string lastPartialJoin, string remainingJoins)
            : base(controller)
        {
            this.table = table;

            CachedTableConstructor ctr = this.Constructor = new CachedTableConstructor(this, aliasGenerator);

            //Query
            using (ObjectName.OverrideOptions(new ObjectNameOptions {
                AvoidDatabaseName = true
            }))
            {
                string select = "SELECT\r\n{0}\r\nFROM {1} {2}\r\n".FormatWith(
                    ctr.table.Columns.Values.ToString(c => ctr.currentAlias + "." + c.Name.SqlEscape(), ",\r\n"),
                    table.Name.ToString(),
                    ctr.currentAlias.ToString());

                ctr.remainingJoins = lastPartialJoin + ctr.currentAlias + "." + table.BackReference.Name.SqlEscape() + "\r\n" + remainingJoins;

                query = new SqlPreCommandSimple(select);
            }

            //Reader
            {
                rowReader = ctr.GetRowReader();
            }

            //Completer
            {
                List <Expression> instructions = new List <Expression>
                {
                    Expression.Assign(ctr.origin, Expression.Convert(CachedTableConstructor.originObject, ctr.tupleType)),
                    Expression.Assign(result, ctr.MaterializeField(table.Field))
                };
                var ci = typeof(MList <T> .RowIdElement).GetConstructor(new [] { typeof(T), typeof(PrimaryKey), typeof(int?) });

                var order = table.Order == null?Expression.Constant(null, typeof(int?)) :
                                ctr.GetTupleProperty(table.Order).Nullify();

                instructions.Add(Expression.New(ci, result, CachedTableConstructor.NewPrimaryKey(ctr.GetTupleProperty(table.PrimaryKey)), order));

                var block = Expression.Block(typeof(MList <T> .RowIdElement), new[] { ctr.origin, result }, instructions);

                activatorExpression = Expression.Lambda <Func <object, IRetriever, MList <T> .RowIdElement> >(block, CachedTableConstructor.originObject, CachedTableConstructor.retriever);

                activator = activatorExpression.Compile();

                parentIdGetter = ctr.GetPrimaryKeyGetter(table.BackReference);
                rowIdGetter    = ctr.GetPrimaryKeyGetter(table.PrimaryKey);
            }

            relationalRows = new ResetLazy <Dictionary <PrimaryKey, Dictionary <PrimaryKey, object> > >(() =>
            {
                CacheLogic.AssertSqlDependencyStarted();

                var connector = (SqlConnector)Connector.Current;

                var subConnector = connector.ForDatabase(table.Name.Schema?.Database);

                Dictionary <PrimaryKey, Dictionary <PrimaryKey, object> > result = new Dictionary <PrimaryKey, Dictionary <PrimaryKey, object> >();

                using (MeasureLoad())
                    using (Connector.Override(subConnector))
                        using (Transaction tr = Transaction.ForceNew(IsolationLevel.ReadCommitted))
                        {
                            if (CacheLogic.LogWriter != null)
                            {
                                CacheLogic.LogWriter.WriteLine("Load {0}".FormatWith(GetType().TypeName()));
                            }

                            ((SqlConnector)Connector.Current).ExecuteDataReaderOptionalDependency(query, OnChange, fr =>
                            {
                                object obj          = rowReader(fr);
                                PrimaryKey parentId = parentIdGetter(obj);
                                var dic             = result.TryGetC(parentId);
                                if (dic == null)
                                {
                                    result[parentId] = dic = new Dictionary <PrimaryKey, object>();
                                }

                                dic[rowIdGetter(obj)] = obj;
                            });
                            tr.Commit();
                        }

                return(result);
            }, mode: LazyThreadSafetyMode.ExecutionAndPublication);
        }
Beispiel #10
0
        public CachedTable(ICacheLogicController controller, AliasGenerator aliasGenerator, string lastPartialJoin, string remainingJoins)
            : base(controller)
        {
            this.table = Schema.Current.Table(typeof(T));

            CachedTableConstructor ctr = this.Constructor = new CachedTableConstructor(this, aliasGenerator);

            //Query
            using (ObjectName.OverrideOptions(new ObjectNameOptions {
                AvoidDatabaseName = true
            }))
            {
                string select = "SELECT\r\n{0}\r\nFROM {1} {2}\r\n".FormatWith(
                    Table.Columns.Values.ToString(c => ctr.currentAlias + "." + c.Name.SqlEscape(), ",\r\n"),
                    table.Name.ToString(),
                    ctr.currentAlias.ToString());

                ctr.remainingJoins = lastPartialJoin == null ? null : lastPartialJoin + ctr.currentAlias + ".Id\r\n" + remainingJoins;

                if (ctr.remainingJoins != null)
                {
                    select += ctr.remainingJoins;
                }

                query = new SqlPreCommandSimple(select);
            }


            //Reader
            {
                rowReader = ctr.GetRowReader();
            }

            //Completer
            {
                ParameterExpression me = Expression.Parameter(typeof(T), "me");

                var block = ctr.MaterializeEntity(me, table);

                completerExpression = Expression.Lambda <Action <object, IRetriever, T> >(block, CachedTableConstructor.originObject, CachedTableConstructor.retriever, me);

                completer = completerExpression.Compile();

                idGetter = ctr.GetPrimaryKeyGetter((IColumn)table.PrimaryKey);
            }

            rows = new ResetLazy <Dictionary <PrimaryKey, object> >(() =>
            {
                CacheLogic.AssertSqlDependencyStarted();

                var connector = (SqlConnector)Connector.Current;
                Table table   = connector.Schema.Table(typeof(T));

                var subConnector = connector.ForDatabase(table.Name.Schema?.Database);

                Dictionary <PrimaryKey, object> result = new Dictionary <PrimaryKey, object>();
                using (MeasureLoad())
                    using (Connector.Override(subConnector))
                        using (Transaction tr = Transaction.ForceNew(IsolationLevel.ReadCommitted))
                        {
                            if (CacheLogic.LogWriter != null)
                            {
                                CacheLogic.LogWriter.WriteLine("Load {0}".FormatWith(GetType().TypeName()));
                            }

                            ((SqlConnector)Connector.Current).ExecuteDataReaderOptionalDependency(query, OnChange, fr =>
                            {
                                object obj            = rowReader(fr);
                                result[idGetter(obj)] = obj; //Could be repeated joins
                            });
                            tr.Commit();
                        }

                return(result);
            }, mode: LazyThreadSafetyMode.ExecutionAndPublication);

            if (!CacheLogic.WithSqlDependency && lastPartialJoin.HasText()) //Is semi
            {
                semiCachedController = new SemiCachedController <T>(this);
            }
        }
Beispiel #11
0
 public static FluentInclude <T> WithCache <T>(this FluentInclude <T> fi)
     where T : Entity
 {
     CacheLogic.TryCacheTable(fi.SchemaBuilder, typeof(T));
     return(fi);
 }
Beispiel #12
0
        public static List <T> ToListWithInvalidation <T>(this IQueryable <T> simpleQuery, Type type, string exceptionContext, Action <SqlNotificationEventArgs> invalidation)
        {
            if (!WithSqlDependency)
            {
                throw new InvalidOperationException("ToListWithInvalidation requires SqlDependency");
            }

            ITranslateResult tr;

            using (ObjectName.OverrideOptions(new ObjectNameOptions {
                AvoidDatabaseName = true
            }))
                tr = ((DbQueryProvider)simpleQuery.Provider).GetRawTranslateResult(simpleQuery.Expression);

            OnChangeEventHandler onChange = (object sender, SqlNotificationEventArgs args) =>
            {
                try
                {
                    if (args.Type != SqlNotificationType.Change)
                    {
                        throw new InvalidOperationException(
                                  "Problems with SqlDependency (Type : {0} Source : {1} Info : {2}) on query: \r\n{3}"
                                  .FormatWith(args.Type, args.Source, args.Info, tr.MainCommand.PlainSql()));
                    }

                    if (args.Info == SqlNotificationInfo.PreviousFire)
                    {
                        throw new InvalidOperationException("The same transaction that loaded the data is invalidating it!")
                              {
                                  Data = { { "query", tr.MainCommand.PlainSql() } }
                              }
                    }
                    ;

                    if (CacheLogic.LogWriter != null)
                    {
                        CacheLogic.LogWriter.WriteLine("Change ToListWithInvalidations {0} {1}".FormatWith(typeof(T).TypeName()), exceptionContext);
                    }

                    invalidation(args);
                }
                catch (Exception e)
                {
                    e.LogException(c => c.ControllerName = exceptionContext);
                }
            };

            SimpleReader reader = null;

            Expression <Func <IProjectionRow, T> > projectorExpression = (Expression <Func <IProjectionRow, T> >)tr.GetMainProjector();
            Func <IProjectionRow, T> projector = projectorExpression.Compile();

            List <T> list = new List <T>();

            CacheLogic.AssertSqlDependencyStarted();

            Table        table = Schema.Current.Table(type);
            DatabaseName db    = table.Name.Schema?.Database;

            SqlConnector subConnector = ((SqlConnector)Connector.Current).ForDatabase(db);

            if (CacheLogic.LogWriter != null)
            {
                CacheLogic.LogWriter.WriteLine("Load ToListWithInvalidations {0} {1}".FormatWith(typeof(T).TypeName()), exceptionContext);
            }

            using (new EntityCache())
                using (var r = EntityCache.NewRetriever()) {
                    subConnector.ExecuteDataReaderDependency(tr.MainCommand, onChange, StartSqlDependencyAndEnableBrocker, fr =>
                    {
                        if (reader == null)
                        {
                            reader = new SimpleReader(fr, r);
                        }

                        list.Add(projector(reader));
                    }, CommandType.Text);

                    r.CompleteAll();
                }

            return(list);
        }