/// <summary> /// Creates the update command set with the supplied context. /// </summary> /// <param name="context"></param> /// <param name="logger"></param> public EntityUpdateCommands(DbContext context, ILogger logger) { Context = context ?? throw new ArgumentNullException(nameof(context)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); var t = typeof(TEntity); EntityType = Context.Model.FindEntityType(t) ?? throw new ArgumentException($"The entity type {t} does not exist in the {Context.GetType()} model."); Key = EntityType.FindPrimaryKey() ?? throw new ArgumentException($"The entity type {t} does not have a primary key in the {Context.GetType()} model."); var stamps = new[] { "timestamp", "rowversion" }; EntityProperties = EntityType .GetProperties() .Where(x => !stamps.Contains(x.GetColumnType().ToLower())) .ToArray(); var conn = Context.Database.ProviderName; Knowledge = SqlKnowledge.For(conn) ?? throw new ArgumentException($"The {conn} provider does not have registered SQL knowledge."); }
/// <summary> /// Creates a parameterized SQL string from the supplied query. /// </summary> /// <param name="query"></param> /// <param name="logger"></param> public ParameterizedSql(IQueryable <TEntity> query, ILogger logger = null) { _original = query; _info = new QueryInfo(query); DbContext = _info.Context.Context; _logger = logger ?? ((IInfrastructure <IServiceProvider>)DbContext) .Instance .GetService(typeof(ILogger <ParameterizedSql <TEntity> >)) as ILogger <ParameterizedSql <TEntity> >; if (DbContext.Model.FindEntityType(typeof(TEntity)) is null) { _logger?.LogInformation($"The type {typeof(TEntity)} is not part of the data model, creating read-only SQL."); ReadOnly = true; } _knowledge = SqlKnowledge.For(DbContext.Database.ProviderName); _logger?.LogDebug("Generating SQL..."); var cmd = _info.Command; SqlText = cmd.CommandText; var paramNames = cmd.Parameters.Select(x => x.InvariantName).ToArray(); _parameterValues = _info.Context .ParameterValues .Where(v => paramNames.Contains(v.Key)) .ToDictionary( v => "@" + v.Key.TrimStart('@'), v => v.Value ); _logger?.LogDebug(SqlText); _logger?.LogDebug("Params: " + string.Join(", ", _parameterValues.Select(x => x.Key))); var rip = SelectRipper.Match(SqlText); if (!rip.Success) { throw new ArgumentException( "The generated SQL does not match the extraction regular expression.\n" + SqlText ); } _action = "SELECT"; _fromClause = rip.Groups["FROM"].Value.Trim(); _whereClause = rip.Groups["WHERE"].Value.Trim(); IsGrouped = !string.IsNullOrWhiteSpace(rip.Groups["GROUPBY"].Value); HasWithExpression = !string.IsNullOrWhiteSpace(rip.Groups["WITH"].Value); var sel = rip.Groups["SELECTION"].Value.Trim(); var aliasSplit = sel.IndexOf('.'); if (aliasSplit <= 0) { _tableAlias = ""; } else { var tbl = sel.Substring(0, aliasSplit); _tableAlias = _knowledge.UnquoteObjectName(tbl); } if (!ReadOnly) { if (string.IsNullOrEmpty(_tableAlias)) { _tableAlias = _info.Expression.Tables.First().Alias; } var tex = _info.Expression.Tables.FirstOrDefault(x => x.Alias == _tableAlias); if (tex is null) { ReadOnly = true; _logger?.LogInformation($"Failed to locate record set named {_tableAlias}."); } else if (tex is TableExpression tt) { if (!string.IsNullOrEmpty(tt.Schema) && tt.Schema != "dbo") { _tableName = _knowledge.QuoteObjectName(tt.Schema) + '.' + _knowledge.QuoteObjectName(tt.Name); } else { _tableName = _knowledge.QuoteObjectName(tt.Name); } } else { ReadOnly = true; _logger?.LogInformation($"Failed to locate a table expression named {_tableAlias}."); } } }