1 //---------------------------------------------------------------------
2 // <copyright file="DbCommandTree.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 namespace System.Data.Common.CommandTrees
12 using System.Collections.Generic;
13 using System.Data.Common.CommandTrees.Internal;
14 using System.Data.Common.Utils;
15 using System.Data.Metadata.Edm;
18 using System.Text.RegularExpressions;
21 /// Describes the different "kinds" (classes) of command trees.
23 internal enum DbCommandTreeKind
33 /// DbCommandTree is the abstract base type for the Delete, Query, Insert and Update DbCommandTree types.
35 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
36 public abstract class DbCommandTree
38 // Metadata collection
39 private readonly MetadataWorkspace _metadata;
40 private readonly DataSpace _dataSpace;
43 /// Initializes a new command tree with a given metadata workspace.
45 /// <param name="metadata">The metadata workspace against which the command tree should operate.</param>
46 /// <param name="dataSpace">The logical 'space' that metadata in the expressions used in this command tree must belong to.</param>
47 internal DbCommandTree(MetadataWorkspace metadata, DataSpace dataSpace)
49 // Ensure the metadata workspace is non-null
50 EntityUtil.CheckArgumentNull(metadata, "metadata");
52 // Ensure that the data space value is valid
53 if (!DbCommandTree.IsValidDataSpace(dataSpace))
55 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_CommandTree_InvalidDataSpace, "dataSpace");
59 // Create the tree's metadata workspace and initalize commonly used types.
61 MetadataWorkspace effectiveMetadata = new MetadataWorkspace();
63 //While EdmItemCollection and StorageitemCollections are required
64 //ObjectItemCollection may or may not be registered on the workspace yet.
65 //So register the ObjectItemCollection if it exists.
66 ItemCollection objectItemCollection;
67 if (metadata.TryGetItemCollection(DataSpace.OSpace, out objectItemCollection))
69 effectiveMetadata.RegisterItemCollection(objectItemCollection);
71 effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.CSpace));
72 effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.CSSpace));
73 effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.SSpace));
75 this._metadata = effectiveMetadata;
76 this._dataSpace = dataSpace;
80 /// Gets the name and corresponding type of each parameter that can be referenced within this command tree.
82 public IEnumerable<KeyValuePair<string, TypeUsage>> Parameters
86 return this.GetParameters();
90 #region Internal Implementation
93 /// Gets the kind of this command tree.
95 internal abstract DbCommandTreeKind CommandTreeKind { get; }
98 /// Gets the name and type of each parameter declared on the command tree.
100 /// <returns></returns>
101 internal abstract IEnumerable<KeyValuePair<string, TypeUsage>> GetParameters();
104 /// Gets the metadata workspace used by this command tree.
106 internal MetadataWorkspace MetadataWorkspace { get { return _metadata; } }
109 /// Gets the data space in which metadata used by this command tree must reside.
111 internal DataSpace DataSpace { get { return _dataSpace; } }
113 #region Dump/Print Support
115 internal void Dump(ExpressionDumper dumper)
118 // Dump information about this command tree to the specified ExpressionDumper
120 // First dump standard information - the DataSpace of the command tree and its parameters
122 Dictionary<string, object> attrs = new Dictionary<string, object>();
123 attrs.Add("DataSpace", this.DataSpace);
124 dumper.Begin(this.GetType().Name, attrs);
127 // The name and type of each Parameter in turn is added to the output
129 dumper.Begin("Parameters", null);
130 foreach (KeyValuePair<string, TypeUsage> param in this.Parameters)
132 Dictionary<string, object> paramAttrs = new Dictionary<string, object>();
133 paramAttrs.Add("Name", param.Key);
134 dumper.Begin("Parameter", paramAttrs);
135 dumper.Dump(param.Value, "ParameterType");
136 dumper.End("Parameter");
138 dumper.End("Parameters");
141 // Delegate to the derived type's implementation that dumps the structure of the command tree
143 this.DumpStructure(dumper);
146 // Matching call to End to correspond with the call to Begin above
148 dumper.End(this.GetType().Name);
151 internal abstract void DumpStructure(ExpressionDumper dumper);
153 internal string DumpXml()
156 // This is a convenience method that dumps the command tree in an XML format.
157 // This is intended primarily as a debugging aid to allow inspection of the tree structure.
159 // Create a new MemoryStream that the XML dumper should write to.
161 MemoryStream stream = new MemoryStream();
166 XmlExpressionDumper dumper = new XmlExpressionDumper(stream);
169 // Dump this tree and then close the XML dumper so that the end document tag is written
170 // and the output is flushed to the stream.
176 // Construct a string from the resulting memory stream and return it to the caller
178 return XmlExpressionDumper.DefaultEncoding.GetString(stream.ToArray());
181 internal string Print()
183 return this.PrintTree(new ExpressionPrinter());
186 internal abstract string PrintTree(ExpressionPrinter printer);
190 internal static bool IsValidDataSpace(DataSpace dataSpace)
192 return (DataSpace.OSpace == dataSpace ||
193 DataSpace.CSpace == dataSpace ||
194 DataSpace.SSpace == dataSpace);
197 internal static bool IsValidParameterName(string name)
199 return (!StringUtil.IsNullOrEmptyOrWhiteSpace(name) &&
200 _paramNameRegex.IsMatch(name));
202 private static readonly Regex _paramNameRegex = new Regex("^([A-Za-z])([A-Za-z0-9_])*$");