1 //---------------------------------------------------------------------
2 // <copyright file="RowType.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System.Collections.Generic;
11 using System.Globalization;
12 using System.Data.Common;
14 using System.Data.Objects.ELinq;
15 using System.Threading;
16 using System.Diagnostics;
18 namespace System.Data.Metadata.Edm
21 /// Represents the Edm Row Type
23 public sealed class RowType : StructuralType
25 private ReadOnlyMetadataCollection<EdmProperty> _properties;
26 private readonly InitializerMetadata _initializerMetadata;
30 /// Initializes a new instance of RowType class with the given list of members
32 /// <param name="properties">properties for this row type</param>
33 /// <exception cref="System.ArgumentException">Thrown if any individual property in the passed in properties argument is null</exception>
34 internal RowType(IEnumerable<EdmProperty> properties)
35 : this(properties, null)
40 /// Initializes a RowType with the given members and initializer metadata
42 internal RowType(IEnumerable<EdmProperty> properties, InitializerMetadata initializerMetadata)
43 : base(GetRowTypeIdentityFromProperties(CheckProperties(properties), initializerMetadata), EdmConstants.TransientNamespace, (DataSpace)(-1))
45 // Initialize the properties.
46 if (null != properties)
48 foreach (EdmProperty property in properties)
50 this.AddProperty(property);
54 _initializerMetadata = initializerMetadata;
56 // Row types are immutable, so now that we're done initializing, set it
66 /// Gets or sets LINQ initializer Metadata for this row type. If there is no associated
67 /// initializer type, value is null.
69 internal InitializerMetadata InitializerMetadata
71 get { return _initializerMetadata; }
75 /// Returns the kind of the type
77 public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.RowType; } }
80 /// Returns the list of properties for this row type
83 /// Returns just the properties from the collection
84 /// of members on this type
86 public ReadOnlyMetadataCollection<EdmProperty> Properties
90 Debug.Assert(IsReadOnly, "this is a wrapper around this.Members, don't call it during metadata loading, only call it after the metadata is set to readonly");
91 if (null == _properties)
93 Interlocked.CompareExchange(ref _properties,
94 new FilteredReadOnlyMetadataCollection<EdmProperty, EdmMember>(
95 this.Members, Helper.IsEdmProperty), null);
105 /// <param name="property">The property to add</param>
106 private void AddProperty(EdmProperty property)
108 EntityUtil.GenericCheckArgumentNull(property, "property");
113 /// Validates a EdmMember object to determine if it can be added to this type's
114 /// Members collection. If this method returns without throwing, it is assumed
115 /// the member is valid.
117 /// <param name="member">The member to validate</param>
118 /// <exception cref="System.ArgumentException">Thrown if the member is not a EdmProperty</exception>
119 internal override void ValidateMemberForAdd(EdmMember member)
121 Debug.Assert(Helper.IsEdmProperty(member), "Only members of type Property may be added to Row types.");
125 /// Calculates the row type identity that would result from
126 /// a given set of properties.
128 /// <param name="properties">The properties that determine the row type's structure</param>
129 /// <param name="initializerMetadata">Metadata describing materialization of this row type</param>
130 /// <returns>A string that identifies the row type</returns>
131 private static string GetRowTypeIdentityFromProperties(IEnumerable<EdmProperty> properties, InitializerMetadata initializerMetadata)
133 // The row type identity is formed as follows:
134 // "rowtype[" + a comma-separated list of property identities + "]"
135 StringBuilder identity = new StringBuilder("rowtype[");
137 if (null != properties)
140 // For each property, append the type name and facets.
141 foreach (EdmProperty property in properties)
145 identity.Append(",");
147 identity.Append("(");
148 identity.Append(property.Name);
149 identity.Append(",");
150 property.TypeUsage.BuildIdentity(identity);
151 identity.Append(")");
155 identity.Append("]");
157 if (null != initializerMetadata)
159 identity.Append(",").Append(initializerMetadata.Identity);
162 return identity.ToString();
166 private static IEnumerable<EdmProperty> CheckProperties(IEnumerable<EdmProperty> properties)
168 if (null != properties)
171 foreach (EdmProperty prop in properties)
175 throw EntityUtil.CollectionParameterElementIsNull("properties");
183 throw EntityUtil.ArgumentOutOfRange("properties");
194 /// EdmEquals override verifying the equivalence of all members and their type usages.
196 /// <param name="item"></param>
197 /// <returns></returns>
198 internal override bool EdmEquals(MetadataItem item)
200 // short-circuit if this and other are reference equivalent
201 if (Object.ReferenceEquals(this, item)) { return true; }
203 // check type of item
204 if (null == item || BuiltInTypeKind.RowType != item.BuiltInTypeKind) { return false; }
205 RowType other = (RowType)item;
207 // check each row type has the same number of members
208 if (this.Members.Count != other.Members.Count) { return false; }
210 // verify all members are equivalent
211 for (int ordinal = 0; ordinal < this.Members.Count; ordinal++)
213 EdmMember thisMember = this.Members[ordinal];
214 EdmMember otherMember = other.Members[ordinal];
216 // if members are different, return false
217 if (!thisMember.EdmEquals(otherMember) ||
218 !thisMember.TypeUsage.EdmEquals(otherMember.TypeUsage))