public override bool IsEqualTo(TableExpression expression) { SubSelectExpression subSelectTable = expression as SubSelectExpression; if (subSelectTable == null) return false; return Name == expression.Name && JoinID == expression.JoinID && Select == subSelectTable.Select; }
public ColumnExpression(TableExpression table, DbColumnInfo columnInfo) : base(SqlExpressionType.Column, GetMemberType(columnInfo)) { Table = table; ColumnInfo = columnInfo; Name = ColumnInfo.ColumnName; }
public NonQueryLinqCommandData(LinqCommand baseLinqCommand, SelectExpression baseSelect, TableExpression targetTable, bool isSingleTable) { BaseLinqCommand = baseLinqCommand; BaseSelect = baseSelect; TargetTable = targetTable; IsSingleTableCommand = isSingleTable; }
/// <summary> /// Set table join /// </summary> /// <param name="joinType"></param> /// <param name="joinedTable"></param> /// <param name="joinExpression"></param> public void Join(TableJoinType joinType, TableExpression joinedTable, Expression joinExpression) { //RI: special case - inner joins on top of outer joins should become outer joins as well if (joinedTable.JoinedTable != null && (joinedTable.JoinType & TableJoinType.FullOuter) != 0) joinType |= joinedTable.JoinType; JoinExpression = joinExpression; JoinType = joinType; JoinedTable = joinedTable; }
public virtual bool IsEqualTo(TableExpression table) { return Name == table.Name && JoinID == table.JoinID && this.Alias == table.Alias; //RI: added Alias comparison }
/// <summary> /// Registers a column /// This method requires the table to be already registered /// </summary> /// <param name="table"></param> /// <param name="name"></param> /// <param name="context"></param> /// <returns></returns> public ColumnExpression RegisterColumn(TableExpression table, string name, TranslationContext context) { var queryColumn = GetRegisteredColumn(table, name, context); if (queryColumn == null) { table = RegisterTable(table, context); queryColumn = CreateColumn(table, name, context); context.CurrentSelect.Columns.Add(queryColumn); } return queryColumn; }
public override Expression Mutate(System.Collections.Generic.IList<Expression> newOperands) { if (newOperands != null && newOperands.Count > 0) Table = (TableExpression) newOperands[0]; return this; }
public override string GetTable(TableExpression tableExpression) { var options = tableExpression.LockOptions; string hint = null; if (options.IsSet(LockOptions.ForUpdate)) hint = "UpdLock"; // hint = "RepeatableRead, RowLock"; else if (options.IsSet(LockOptions.SharedRead)) hint = null; // "Serializable"; //turns out we do not need any hint here if we run in Snapshot level // hint = "RepeatableRead, RowLock"; else if (options.IsSet(LockOptions.NoLock)) hint = "NOLOCK"; var table = base.GetTable(tableExpression); //Note: for MS SQL, table alias (if present) goes before the hint ( ... FROM Tbl t WITH(NOLOCK) ...), so it works as coded if (hint!=null) table += " WITH(" + hint + ")"; return table; }
public virtual bool IsEqualTo(TableExpression table) { return(Name == table.Name && JoinID == table.JoinID && this.Alias == table.Alias); //RI: added Alias comparison }
private Expression BuildListPropertyJoinExpression(TableExpression fromTable, TableExpression toTable, EntityMemberInfo refMember, TranslationContext context) { var fromKeyMembers = refMember.ReferenceInfo.FromKey.ExpandedKeyMembers; var toKeyMembers = refMember.ReferenceInfo.ToKey.ExpandedKeyMembers; var clauses = new List<Expression>(); for (int i = 0; i < fromKeyMembers.Count; i++) { var mFrom = fromKeyMembers[i]; var mTo = toKeyMembers[i]; var colFrom = RegisterColumn(fromTable, mFrom.Member.ClrClassMemberInfo, context); var colTo = RegisterColumn(toTable, mTo.Member.ClrClassMemberInfo, context); var eqExpr = MakeEqual(colFrom, colTo); clauses.Add(eqExpr); } //Build AND var result = clauses[0]; for (int i = 1; i < clauses.Count; i++) result = Expression.And(result, clauses[i]); return result; }
/// <summary> /// Promotes a table to a common parent between its current scope and our current scope /// </summary> /// <param name="tableExpression"></param> /// <param name="context"></param> /// <returns></returns> protected virtual TableExpression PromoteTable(TableExpression tableExpression, TranslationContext context) { int currentIndex = 0; SelectExpression oldSelect = null; SelectExpression commonScope = null; TableExpression foundTable = null; do { // take a select oldSelect = context.SelectExpressions[currentIndex]; // look for a common scope if (oldSelect != context.CurrentSelect) { commonScope = FindCommonScope(oldSelect, context.CurrentSelect); if (commonScope != null) // if a common scope exists, look for an equivalent table in that select for (int tableIndex = 0; tableIndex < oldSelect.Tables.Count && foundTable == null; tableIndex++) { if (oldSelect.Tables[tableIndex].IsEqualTo(tableExpression)) { // found a matching table! foundTable = oldSelect.Tables[tableIndex]; } } } ++currentIndex; } while (currentIndex < context.SelectExpressions.Count && foundTable == null); if (foundTable != null) { oldSelect.Tables.Remove(foundTable); commonScope.Tables.Add(foundTable); } return foundTable; }
/// <summary> /// Returns a registered column, or null if not found /// This method requires the table to be already registered /// </summary> /// <param name="table"></param> /// <param name="name"></param> /// <param name="context"></param> /// <returns></returns> protected virtual ColumnExpression GetRegisteredColumn(TableExpression table, string name, TranslationContext context) { return (from queryColumn in context.EnumerateScopeColumns() where queryColumn.Table.IsEqualTo(table) && queryColumn.Name == name // where queryColumn.Table == table && queryColumn.Name == name // - RI: this does not work select queryColumn).SingleOrDefault(); }
// RI: new stuff, optimized entity reader protected virtual Expression GetOutputTableReader(TableExpression tableExpression, ParameterExpression dataRecordParameter, ParameterExpression sessionParameter, TranslationContext context) { // Note: we have to create materializer each time, because column indexes in output can change from query to query var entMatzer = new EntityMaterializer(tableExpression.TableInfo); var allColExprs = RegisterAllColumns(tableExpression, context); foreach (var col in allColExprs) { var colIndex = RegisterOutputValue(col, context); entMatzer.AddColumn(col.ColumnInfo, colIndex); } var entMatzerConst = Expression.Constant(entMatzer); var callReadEntity = Expression.Call(entMatzerConst, EntityMaterializer.ReadMethodInfo, dataRecordParameter, sessionParameter); var convExpr = Expression.Convert(callReadEntity, tableExpression.Type); return convExpr; }
public ColumnExpression CreateColumn(TableExpression table, string memberName, TranslationContext context) { var col = table.TableInfo.GetColumnByMemberName(memberName); Util.Check(col != null, "Column for member [{0}] not found in table {1}. Member type is not supported by LINQ.", memberName, table.Name); return new ColumnExpression(table, col); }
/// <summary> /// Returns an existing table or registers the current one /// </summary> /// <param name="tableExpression"></param> /// <param name="context"></param> /// <returns>A registered table or the current newly registered one</returns> public virtual TableExpression RegisterTable(TableExpression tableExpression, TranslationContext context) { // 1. Find the table in current scope var foundTableExpression = (from t in context.EnumerateScopeTables() where t.IsEqualTo(tableExpression) select t).FirstOrDefault(); if (foundTableExpression != null) return foundTableExpression; // 2. Find it in all scopes, and promote it to current scope. foundTableExpression = PromoteTable(tableExpression, context); if (foundTableExpression != null) return foundTableExpression; // 3. Add it context.CurrentSelect.Tables.Add(tableExpression); return tableExpression; }
public ColumnExpression RegisterColumn(TableExpression tableExpression, MemberInfo memberInfo, TranslationContext context) { return RegisterColumn(tableExpression, memberInfo.Name, context); }
private Expression AnalyzeEntityListMember(TableExpression table, PropertyInfo property, TranslationContext context) { var propType = property.PropertyType; if (!propType.IsEntitySequence()) return null; var modelInfo = context.DbModel.EntityApp.Model; var masterEntInfo = modelInfo.GetEntityInfo(table.Type); var entMember = masterEntInfo.GetMember(property.Name); Util.Check(entMember != null, "Failed to find member {0} on entity {1}.", property.Name, masterEntInfo.Name); Util.Check(entMember.Kind == MemberKind.EntityList, "Internal LINQ error: expected List member ({0}.{1}", masterEntInfo.Name, property.Name); var listInfo = entMember.ChildListInfo; Expression whereExpr; switch(listInfo.RelationType) { case EntityRelationType.ManyToOne: var childTable = CreateTable(listInfo.TargetEntity.EntityType, context); whereExpr = BuildListPropertyJoinExpression(childTable, table, listInfo.ParentRefMember, context); if (!string.IsNullOrWhiteSpace(listInfo.Filter)) { var filterExpr = new TableFilterExpression(childTable, listInfo.Filter); whereExpr = Expression.And(whereExpr, filterExpr); } context.CurrentSelect.Where.Add(whereExpr); return childTable; case EntityRelationType.ManyToMany: var linkTable = CreateTable(listInfo.LinkEntity.EntityType, context); whereExpr = BuildListPropertyJoinExpression(linkTable, table, listInfo.ParentRefMember, context); context.CurrentSelect.Where.Add(whereExpr); var targetTable = RegisterAssociation(linkTable, listInfo.OtherEntityRefMember, context); return targetTable; } return null; //never happens }
private IList<MemberInfo> GetAssociationMembers(TableExpression thisTableExpression, EntityMemberInfo member, out IList<MemberInfo> otherKey, out TableJoinType joinType, out string joinID) { switch(member.Kind) { case MemberKind.EntityRef: // by default, join is inner joinType = TableJoinType.Inner; joinID = member.MemberName; var otherType = member.ReferenceInfo.ToKey.Entity.ClassInfo.Type; otherKey = member.ReferenceInfo.ToKey.ExpandedKeyMembers.Select(km => (MemberInfo) km.Member.ClrClassMemberInfo).ToList(); var thisKey = member.ReferenceInfo.FromKey.ExpandedKeyMembers.Select(km => (MemberInfo)km.Member.ClrClassMemberInfo).ToList(); if(member.Flags.IsSet(EntityMemberFlags.Nullable)) joinType |= TableJoinType.LeftOuter; return thisKey; case MemberKind.Transient: if(!member.Flags.IsSet(EntityMemberFlags.FromOneToOneRef)) break; joinType = TableJoinType.LeftOuter; joinID = member.MemberName; var targetEnt = this._dbModel.EntityApp.Model.GetEntityInfo(member.DataType, throwIfNotFound: true); otherKey = targetEnt.PrimaryKey.ExpandedKeyMembers.Select(km => km.Member.ClrClassMemberInfo).ToList(); var thisPk = member.Entity.PrimaryKey.ExpandedKeyMembers.Select(km => km.Member.ClrClassMemberInfo).ToList(); return thisPk; } Util.Throw("Cannot create JOIN expression for property {0}, property not supported in LINQ.", member); otherKey = null; joinType = TableJoinType.Default; joinID = null; return null; }
public virtual TableExpression CreateTable(Type tableType, TranslationContext context, LockOptions lockOptions = LockOptions.None) { var tableInfo = _dbModel.GetTable(tableType); var tableExpr = new TableExpression(tableType, tableInfo.FullName, tableInfo, lockOptions); return tableExpr; }
/// <summary> /// Registers all columns of a table. /// </summary> /// <param name="tableExpression"></param> /// <param name="context"></param> /// <returns></returns> public virtual IList<ColumnExpression> RegisterAllColumns(TableExpression tableExpression, TranslationContext context) { var result = new List<ColumnExpression>(); foreach (var colInfo in tableExpression.TableInfo.Columns) { if (colInfo.Member == null) continue; var colExpr = RegisterColumn(tableExpression, colInfo.Member.MemberName, context); result.Add(colExpr); } return result; }
/// <summary> /// Set table join /// </summary> /// <param name="joinType"></param> /// <param name="joinedTable"></param> /// <param name="joinExpression"></param> /// <param name="joinID"></param> public void Join(TableJoinType joinType, TableExpression joinedTable, Expression joinExpression, string joinID) { Join(joinType, joinedTable, joinExpression); JoinID = joinID; }
public virtual string GetTable(TableExpression tableExpr) { var result = GetSafeName(tableExpr.Name); if (!string.IsNullOrWhiteSpace(tableExpr.Alias)) result += " " + GetTableAlias(tableExpr.Alias); return result; }
public TableFilterExpression(TableExpression table, string filter) : base(SqlExpressionType.TableFilter, typeof(bool)) { Table = table; Filter = filter; }
/// <summary> /// Replaces a table selection by a selection of all mapped columns (ColumnExpressions). /// ColumnExpressions will be replaced at a later time by the tier splitter /// </summary> /// <param name="tableExpression"></param> /// <param name="context"></param> /// <returns></returns> protected virtual Expression GetSelectTableExpression(TableExpression tableExpression, TranslationContext context) { var bindings = new List<MemberBinding>(); foreach (var columnExpression in RegisterAllColumns(tableExpression, context)) { var binding = Expression.Bind((MethodInfo) columnExpression.ColumnInfo.Member.ClrClassMemberInfo, columnExpression); bindings.Add(binding); } var newExpression = Expression.New(tableExpression.Type); return Expression.MemberInit(newExpression, bindings); }
public virtual TableExpression RegisterAssociation(TableExpression tableExpression, EntityMemberInfo refMember, TranslationContext context) { IList<MemberInfo> otherKeys; TableJoinType joinType; string joinID; var theseKeys = GetAssociationMembers(tableExpression, refMember, out otherKeys, out joinType, out joinID); // if the memberInfo has no corresponding association, we get a null, that we propagate if (theseKeys == null) return null; // the current table has the foreign key, the other table the referenced (usually primary) key if (theseKeys.Count != otherKeys.Count) Util.Throw("S0128: Association arguments (FK and ref'd PK) don't match"); // we first create the table, with the JoinID, and we MUST complete the table later, with the Join() method var otherType = refMember.DataType; var otherTableInfo = context.DbModel.GetTable(otherType); var otherTableExpression = CreateTable(otherType, context); // new TableExpression(otherType, otherTableInfo.FullName, otherTableInfo, joinID); otherTableExpression = RegisterTable(otherTableExpression, context); Expression joinExpression = null; var createdColumns = new List<ColumnExpression>(); for (int keyIndex = 0; keyIndex < theseKeys.Count; keyIndex++) { // joinedKey is registered, even if unused by final select (required columns will be filtered anyway) Expression otherKey = RegisterColumn(otherTableExpression, otherKeys[keyIndex], context); // foreign is created, we will store it later if this assocation is registered too Expression thisKey = CreateColumn(tableExpression, theseKeys[keyIndex].Name, context); createdColumns.Add((ColumnExpression)thisKey); // the other key is set as left operand, this must be this way // since some vendors (SQL Server) don't support the opposite var referenceExpression = MakeEqual(otherKey, thisKey); // if we already have a join expression, then we have a double condition here, so "AND" it if (joinExpression != null) joinExpression = Expression.And(joinExpression, referenceExpression); else joinExpression = referenceExpression; } // we complete the table here, now that we have all join information otherTableExpression.Join(joinType, tableExpression, joinExpression); // our table is created, with the expressions // now check if we didn't register exactly the same var existingTable = (from t in context.EnumerateScopeTables() where t.IsEqualTo(otherTableExpression) select t).SingleOrDefault(); if (existingTable != null) return existingTable; context.CurrentSelect.Tables.Add(otherTableExpression); foreach (var createdColumn in createdColumns) context.CurrentSelect.Columns.Add(createdColumn); return otherTableExpression; }
protected virtual bool MustDeclareAsJoin(IList<TableExpression> tables, TableExpression table) { // Temp hack, trying make all joins if(tables.Count == 1 && table == tables[0]) return false; if(table.JoinExpression == null) return false; return true; /* // the first table can not be declared as join if (table == tables[0]) return false; // we must declare as join, whatever the join is, // if some of the registered tables are registered as complex join if (tables.Any(t => t.JoinType != TableJoinType.Inner)) return table.JoinExpression != null; return false; */ }