public Task <object?> ExecuteAsync(CancellationToken token) { return(SqlServerRetry.RetryAsync(async() => { using (new EntityCache()) using (Transaction tr = new Transaction()) { object?result; using (var retriever = EntityCache.NewRetriever()) { var lookups = new Dictionary <LookupToken, IEnumerable>(); foreach (var child in EagerProjections) { await child.FillAsync(lookups, retriever, token); } using (HeavyProfiler.Log("SQL", () => MainCommand.sp_executesql())) using (var reader = await Executor.UnsafeExecuteDataReaderAsync(MainCommand, token: token)) { ProjectionRowEnumerator <T> enumerator = new ProjectionRowEnumerator <T>(reader.Reader, ProjectorExpression, lookups, retriever, token); IEnumerable <T> enumerable = new ProjectionRowEnumerable <T>(enumerator); try { if (Unique == null) { result = enumerable.ToList(); } else { result = UniqueMethod(enumerable, Unique.Value); } } catch (Exception ex) when(!(ex is OperationCanceledException)) { FieldReaderException fieldEx = enumerator.Reader.CreateFieldReaderException(ex); fieldEx.Command = MainCommand; fieldEx.Row = enumerator.Row; fieldEx.Projector = ProjectorExpression; throw fieldEx; } } foreach (var child in LazyChildProjections) { await child.FillAsync(lookups, retriever, token); } retriever.CompleteAll(); } return tr.Commit(result); } })); }
public static SqlServerVersion?Detect(string connectionString) { return(SqlServerRetry.Retry(() => { using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); var sql = @"SELECT SERVERPROPERTY ('ProductVersion') as ProductVersion, SERVERPROPERTY('ProductLevel') as ProductLevel, SERVERPROPERTY('Edition') as Edition, SERVERPROPERTY('EngineEdition') as EngineEdition"; using (SqlCommand cmd = new SqlCommand(sql, con)) { SqlDataAdapter da = new SqlDataAdapter(cmd); DataTable result = new DataTable(); da.Fill(result); if ((int)result.Rows[0]["EngineEdition"] == (int)EngineEdition.Azure) { return SqlServerVersion.AzureSQL; } var version = (string)result.Rows[0]["ProductVersion"]; switch (version.Before(".")) { case "8": throw new InvalidOperationException("SQL Server 2000 is not supported"); case "9": return SqlServerVersion.SqlServer2005; case "10": return SqlServerVersion.SqlServer2008; case "11": return SqlServerVersion.SqlServer2012; case "12": return SqlServerVersion.SqlServer2014; case "13": return SqlServerVersion.SqlServer2016; case "14": return SqlServerVersion.SqlServer2017; case "15": return SqlServerVersion.SqlServer2019; default: return (SqlServerVersion?)null; } } } })); }
T EnsureConnectionRetry <T>(Func <SqlConnection?, T> action) { if (Transaction.HasTransaction) { return(action(null)); } return(SqlServerRetry.Retry(() => { using (SqlConnection con = new SqlConnection(this.ConnectionString)) { con.Open(); return action(con); } })); }
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); var isPostgres = Schema.Current.Settings.IsPostgres; //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(isPostgres), ",\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> >(() => { return(SqlServerRetry.Retry(() => { CacheLogic.AssertSqlDependencyStarted(); Table table = Connector.Current.Schema.Table(typeof(T)); Dictionary <PrimaryKey, object> result = new Dictionary <PrimaryKey, object>(); using (MeasureLoad()) using (Connector.Override(Connector.Current.ForDatabase(table.Name.Schema?.Database))) using (Transaction tr = Transaction.ForceNew(IsolationLevel.ReadCommitted)) { if (CacheLogic.LogWriter != null) { CacheLogic.LogWriter.WriteLine("Load {0}".FormatWith(GetType().TypeName())); } 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); } }
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); var isPostgres = Schema.Current.Settings.IsPostgres; //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(isPostgres), ", "), table.Name.ToString(), currentAlias.ToString()); select += this.lastPartialJoin + currentAlias + "." + table.PrimaryKey.Name.SqlEscape(isPostgres) + "\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> >(() => { return(SqlServerRetry.Retry(() => { CacheLogic.AssertSqlDependencyStarted(); Dictionary <PrimaryKey, string> result = new Dictionary <PrimaryKey, string>(); using (MeasureLoad()) using (Connector.Override(Connector.Current.ForDatabase(table.Name.Schema?.Database))) using (Transaction tr = Transaction.ForceNew(IsolationLevel.ReadCommitted)) { if (CacheLogic.LogWriter != null) { CacheLogic.LogWriter.WriteLine("Load {0}".FormatWith(GetType().TypeName())); } 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(); } } }
public CachedTableMList(ICacheLogicController controller, TableMList table, AliasGenerator?aliasGenerator, string lastPartialJoin, string?remainingJoins) : base(controller) { this.table = table; var isPostgres = Schema.Current.Settings.IsPostgres; 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(isPostgres), ",\r\n"), table.Name.ToString(), ctr.currentAlias !.ToString()); ctr.remainingJoins = lastPartialJoin + ctr.currentAlias + "." + table.BackReference.Name.SqlEscape(isPostgres) + "\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> > >(() => { return(SqlServerRetry.Retry(() => { CacheLogic.AssertSqlDependencyStarted(); Dictionary <PrimaryKey, Dictionary <PrimaryKey, object> > result = new Dictionary <PrimaryKey, Dictionary <PrimaryKey, object> >(); using (MeasureLoad()) using (Connector.Override(Connector.Current.ForDatabase(table.Name.Schema?.Database))) using (Transaction tr = Transaction.ForceNew(IsolationLevel.ReadCommitted)) { if (CacheLogic.LogWriter != null) { CacheLogic.LogWriter.WriteLine("Load {0}".FormatWith(GetType().TypeName())); } 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); }