internal string[] FormatBlock(SqlBlock block, bool isDebug)
		{
			List<string> results = new List<string>(block.Statements.Count);
			for(int i = 0, n = block.Statements.Count; i < n; i++)
			{
				SqlStatement stmt = block.Statements[i];
				SqlSelect select = stmt as SqlSelect;
				if(select != null && select.DoNotOutput)
				{
					continue;
				}
				results.Add(this.Format(stmt, isDebug));
			}
			return results.ToArray();
		}
		internal ReadOnlyCollection<ReadOnlyCollection<SqlParameterInfo>> ParameterizeBlock(SqlBlock block)
		{
			SqlParameterInfo rowStatus =
				new SqlParameterInfo(
					new SqlParameter(typeof(int), _typeProvider.From(typeof(int)), "@ROWCOUNT", block.SourceExpression)
					);
			List<ReadOnlyCollection<SqlParameterInfo>> list = new List<ReadOnlyCollection<SqlParameterInfo>>();
			for(int i = 0, n = block.Statements.Count; i < n; i++)
			{
				SqlNode statement = block.Statements[i];
				List<SqlParameterInfo> parameters = this.ParameterizeInternal(statement);
				if(i > 0)
				{
					parameters.Add(rowStatus);
				}
				list.Add(parameters.AsReadOnly());
			}
			return list.AsReadOnly();
		}
Exemple #3
0
 internal virtual SqlBlock VisitBlock(SqlBlock b) {
     for (int i = 0, n = b.Statements.Count; i < n; i++) {
         b.Statements[i] = (SqlStatement)this.Visit(b.Statements[i]);
     }
     return b;
 }
		private SqlStatement VisitUpdate(Expression item, LambdaExpression check, LambdaExpression resultSelector)
		{
			if(item == null)
			{
				throw Error.ArgumentNull("item");
			}
			MetaTable metaTable = _services.Model.GetTable(item.Type);
			Expression source = _services.Context.GetTable(metaTable.RowType.Type).Expression;
			Type rowType = metaTable.RowType.Type;

			bool saveAllowDeferred = _allowDeferred;
			_allowDeferred = false;

			try
			{
				Expression seq = source;
				// construct identity predicate based on supplied item
				ParameterExpression p = Expression.Parameter(rowType, "p");
				LambdaExpression idPredicate = Expression.Lambda(Expression.Equal(p, item), p);

				// combine predicate and check expression into single find predicate
				LambdaExpression findPredicate = idPredicate;
				if(check != null)
				{
					findPredicate = Expression.Lambda(Expression.And(Expression.Invoke(findPredicate, p), Expression.Invoke(check, p)), p);
				}
				seq = Expression.Call(typeof(Enumerable), "Where", new Type[] { rowType }, seq, findPredicate);

				// source 'query' is based on table + find predicate
				SqlSelect ss = new RetypeCheckClause().VisitSelect(this.VisitSequence(seq));

				// construct update assignments from 'item' info
				List<SqlAssign> assignments = new List<SqlAssign>();
				ConstantExpression conItem = item as ConstantExpression;
				if(conItem == null)
				{
					throw Error.UpdateItemMustBeConstant();
				}
				if(conItem.Value == null)
				{
					throw Error.ArgumentNull("item");
				}
				// get changes from data services to construct update command
				Type entityType = conItem.Value.GetType();
				MetaType metaType = _services.Model.GetMetaType(entityType);
				ITable table = _services.Context.GetTable(metaType.InheritanceRoot.Type);
				foreach(ModifiedMemberInfo mmi in table.GetModifiedMembers(conItem.Value))
				{
					MetaDataMember mdm = metaType.GetDataMember(mmi.Member);
					assignments.Add(
						new SqlAssign(
							_nodeFactory.Member(ss.Selection, mmi.Member),
							new SqlValue(mdm.Type, _typeProvider.From(mdm.Type), mmi.CurrentValue, true, source),
							source
							));
				}

				SqlUpdate upd = new SqlUpdate(ss, assignments, source);

				if(resultSelector == null)
				{
					return upd;
				}

				SqlSelect select = null;

				// build select to return result
				seq = source;
				seq = Expression.Call(typeof(Enumerable), "Where", new Type[] { rowType }, seq, idPredicate);
				seq = Expression.Call(typeof(Enumerable), "Select", new Type[] { rowType, resultSelector.Body.Type }, seq, resultSelector);
				select = this.VisitSequence(seq);
				select.Where = _nodeFactory.AndAccumulate(
					_nodeFactory.Binary(SqlNodeType.GT, this.GetRowCountExpression(), _nodeFactory.ValueFromObject(0, false, _dominatingExpression)),
					select.Where
					);

				// combine update & select into statement block
				SqlBlock block = new SqlBlock(source);
				block.Statements.Add(upd);
				block.Statements.Add(select);
				return block;
			}
			finally
			{
				_allowDeferred = saveAllowDeferred;
			}
		}
		private SqlStatement VisitInsert(Expression item, LambdaExpression resultSelector)
		{
			if(item == null)
			{
				throw Error.ArgumentNull("item");
			}
			_dominatingExpression = item;

			MetaTable metaTable = _services.Model.GetTable(item.Type);
			Expression source = _services.Context.GetTable(metaTable.RowType.Type).Expression;

			MetaType itemMetaType = null;
			SqlNew sqlItem = null;

			// construct insert assignments from 'item' info
			ConstantExpression conItem = item as ConstantExpression;
			if(conItem == null)
			{
				throw Error.InsertItemMustBeConstant();
			}
			if(conItem.Value == null)
			{
				throw Error.ArgumentNull("item");
			}
			// construct insert based on constant value
			List<SqlMemberAssign> bindings = new List<SqlMemberAssign>();
			itemMetaType = metaTable.RowType.GetInheritanceType(conItem.Value.GetType());
			SqlExpression sqlExprItem = _nodeFactory.ValueFromObject(conItem.Value, true, source);
			foreach(MetaDataMember mm in itemMetaType.PersistentDataMembers)
			{
				if(!mm.IsAssociation && !mm.IsDbGenerated && !mm.IsVersion)
				{
					bindings.Add(new SqlMemberAssign(mm.Member, _nodeFactory.Member(sqlExprItem, mm.Member)));
				}
			}
			ConstructorInfo cons = itemMetaType.Type.GetConstructor(Type.EmptyTypes);
			System.Diagnostics.Debug.Assert(cons != null);
			sqlItem = _nodeFactory.New(itemMetaType, cons, null, null, bindings, item);

			SqlTable tab = _nodeFactory.Table(metaTable, metaTable.RowType, _dominatingExpression);
			SqlInsert sin = new SqlInsert(tab, sqlItem, item);

			if(resultSelector == null)
			{
				return sin;
			}
			else
			{
				MetaDataMember id = itemMetaType.DBGeneratedIdentityMember;
				bool isDbGenOnly = false;
				if(id != null)
				{
					isDbGenOnly = this.IsDbGeneratedKeyProjectionOnly(resultSelector.Body, id);
					if(id.Type == typeof(Guid) && (_converterStrategy & ConverterStrategy.CanOutputFromInsert) != 0)
					{
						sin.OutputKey = new SqlColumn(id.Type, _nodeFactory.Default(id), id.Name, id, null, _dominatingExpression);
						if(!isDbGenOnly)
						{
							sin.OutputToLocal = true;
						}
					}
				}

				SqlSelect result = null;
				SqlSelect preResult = null;
				SqlAlias tableAlias = new SqlAlias(tab);
				SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias);
				System.Diagnostics.Debug.Assert(resultSelector.Parameters.Count == 1);
				_parameterExpressionToSqlExpression.Add(resultSelector.Parameters[0], tableAliasRef);
				SqlExpression projection = this.VisitExpression(resultSelector.Body);

				// build select to return result
				SqlExpression pred = null;
				if(id != null)
				{
					pred = _nodeFactory.Binary(
							SqlNodeType.EQ,
							_nodeFactory.Member(tableAliasRef, id.Member),
							this.GetIdentityExpression(id, sin.OutputKey != null)
							);
				}
				else
				{
					SqlExpression itemExpression = this.VisitExpression(item);
					pred = _nodeFactory.Binary(SqlNodeType.EQ2V, tableAliasRef, itemExpression);
				}
				result = new SqlSelect(projection, tableAlias, resultSelector);
				result.Where = pred;

				// Since we're only projecting back a single generated key, we can
				// optimize the query to a simple selection (e.g. SELECT @@IDENTITY)
				// rather than selecting back from the table.
				if(id != null && isDbGenOnly)
				{
					if(sin.OutputKey == null)
					{
						SqlExpression exp = this.GetIdentityExpression(id, false);
						if(exp.ClrType != id.Type)
						{
							ProviderType sqlType = _nodeFactory.Default(id);
							exp = _nodeFactory.ConvertTo(id.Type, sqlType, exp);
						}
						// The result selector passed in was bound to the table -
						// we need to rebind to the single result as an array projection
						ParameterExpression p = Expression.Parameter(id.Type, "p");
						Expression[] init = new Expression[1] { Expression.Convert(p, typeof(object)) };
						NewArrayExpression arrExp = Expression.NewArrayInit(typeof(object), init);
						LambdaExpression rs = Expression.Lambda(arrExp, p);
						_parameterExpressionToSqlExpression.Add(p, exp);
						SqlExpression proj = this.VisitExpression(rs.Body);
						preResult = new SqlSelect(proj, null, rs);
					}
					else
					{
						// case handled in formatter automatically
					}
					result.DoNotOutput = true;
				}

				// combine insert & result into block
				SqlBlock block = new SqlBlock(_dominatingExpression);
				block.Statements.Add(sin);
				if(preResult != null)
				{
					block.Statements.Add(preResult);
				}
				block.Statements.Add(result);
				return block;
			}
		}
		internal override SqlBlock VisitBlock(SqlBlock block)
		{
			for(int i = 0, n = block.Statements.Count; i < n; i++)
			{
				this.Visit(block.Statements[i]);
				if(i < n - 1)
				{
					SqlSelect select = block.Statements[i + 1] as SqlSelect;
					if(@select == null || [email protected])
					{
						this.NewLine();
						this.NewLine();
					}
				}
			}
			return block;
		}
		internal override SqlBlock VisitBlock(SqlBlock block)
		{
			SqlBlock nb = new SqlBlock(block.SourceExpression);
			foreach(SqlStatement stmt in block.Statements)
			{
				nb.Statements.Add((SqlStatement)this.Visit(stmt));
			}
			return nb;
		}