1 //--------------------------------------------------------------------- 2 // <copyright file="EdmProperty.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // 6 // @owner Microsoft 7 // @backupOwner Microsoft 8 //--------------------------------------------------------------------- 9 10 using System.Data.Common; 11 using System.Threading; 12 13 namespace System.Data.Metadata.Edm 14 { 15 /// <summary> 16 /// Represent the edm property class 17 /// </summary> 18 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")] 19 public sealed class EdmProperty : EdmMember 20 { 21 #region Constructors 22 /// <summary> 23 /// Initializes a new instance of the property class 24 /// </summary> 25 /// <param name="name">name of the property</param> 26 /// <param name="typeUsage">TypeUsage object containing the property type and its facets</param> 27 /// <exception cref="System.ArgumentNullException">Thrown if name or typeUsage arguments are null</exception> 28 /// <exception cref="System.ArgumentException">Thrown if name argument is empty string</exception> EdmProperty(string name, TypeUsage typeUsage)29 internal EdmProperty(string name, TypeUsage typeUsage) 30 : base(name, typeUsage) 31 { 32 EntityUtil.CheckStringArgument(name, "name"); 33 EntityUtil.GenericCheckArgumentNull(typeUsage, "typeUsage"); 34 } 35 #endregion 36 37 #region Fields 38 /// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary> 39 internal readonly System.RuntimeMethodHandle PropertyGetterHandle; 40 41 /// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary> 42 internal readonly System.RuntimeMethodHandle PropertySetterHandle; 43 44 /// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary> 45 internal readonly System.RuntimeTypeHandle EntityDeclaringType; 46 47 /// <summary>cached dynamic method to get the property value from a CLR instance</summary> 48 private Func<object,object> _memberGetter; 49 50 /// <summary>cached dynamic method to set a CLR property value on a CLR instance</summary> 51 private Action<object,object> _memberSetter; 52 #endregion 53 54 /// <summary> 55 /// Initializes a new OSpace instance of the property class 56 /// </summary> 57 /// <param name="name">name of the property</param> 58 /// <param name="typeUsage">TypeUsage object containing the property type and its facets</param> 59 /// <param name="propertyInfo">for the property</param> 60 /// <param name="entityDeclaringType">The declaring type of the entity containing the property</param> EdmProperty(string name, TypeUsage typeUsage, System.Reflection.PropertyInfo propertyInfo, RuntimeTypeHandle entityDeclaringType)61 internal EdmProperty(string name, TypeUsage typeUsage, System.Reflection.PropertyInfo propertyInfo, RuntimeTypeHandle entityDeclaringType) 62 : this(name, typeUsage) 63 { 64 System.Diagnostics.Debug.Assert(name == propertyInfo.Name, "different PropertyName"); 65 if (null != propertyInfo) 66 { 67 System.Reflection.MethodInfo method; 68 69 method = propertyInfo.GetGetMethod(true); // return public or non-public getter 70 PropertyGetterHandle = ((null != method) ? method.MethodHandle : default(System.RuntimeMethodHandle)); 71 72 method = propertyInfo.GetSetMethod(true); // return public or non-public getter 73 PropertySetterHandle = ((null != method) ? method.MethodHandle : default(System.RuntimeMethodHandle)); 74 75 EntityDeclaringType = entityDeclaringType; 76 } 77 } 78 79 /// <summary> 80 /// Returns the kind of the type 81 /// </summary> 82 public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.EdmProperty; } } 83 84 /// <summary> 85 /// Returns true if this property is nullable. 86 /// </summary> 87 /// <remarks> 88 /// Nullability in the conceptual model and store model is a simple indication of whether or not 89 /// the property is considered nullable. Nullability in the object model is more complex. 90 /// When using convention based mapping (as usually happens with POCO entities), a property in the 91 /// object model is considered nullable if and only if the underlying CLR type is nullable and 92 /// the property is not part of the primary key. 93 /// When using attribute based mapping (usually used with entities that derive from the EntityObject 94 /// base class), a property is considered nullable if the IsNullable flag is set to true in the 95 /// <see cref="System.Data.Objects.DataClasses.EdmScalarPropertyAttribute"/> attribute. This flag can 96 /// be set to true even if the underlying type is not nullable, and can be set to false even if the 97 /// underlying type is nullable. The latter case happens as part of default code generation when 98 /// a non-nullable property in the conceptual model is mapped to a nullable CLR type such as a string. 99 /// In such a case, the Entity Framework treats the property as non-nullable even though the CLR would 100 /// allow null to be set. 101 /// There is no good reason to set a non-nullable CLR type as nullable in the object model and this 102 /// should not be done even though the attribute allows it. 103 /// </remarks> 104 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called when the EdmProperty instance is in ReadOnly state</exception> 105 public bool Nullable 106 { 107 get 108 { 109 return (bool)TypeUsage.Facets[DbProviderManifest.NullableFacetName].Value; 110 } 111 } 112 113 /// <summary> 114 /// Returns the default value for this property 115 /// </summary> 116 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called when the EdmProperty instance is in ReadOnly state</exception> 117 public Object DefaultValue 118 { 119 get 120 { 121 return TypeUsage.Facets[DbProviderManifest.DefaultValueFacetName].Value; 122 } 123 } 124 125 /// <summary>cached dynamic method to get the property value from a CLR instance</summary> 126 internal Func<object,object> ValueGetter { 127 get { return _memberGetter; } 128 set 129 { 130 System.Diagnostics.Debug.Assert(null != value, "clearing ValueGetter"); 131 // It doesn't matter which delegate wins, but only one should be jitted 132 Interlocked.CompareExchange(ref _memberGetter, value, null); 133 } 134 } 135 136 /// <summary>cached dynamic method to set a CLR property value on a CLR instance</summary> 137 internal Action<object,object> ValueSetter 138 { 139 get { return _memberSetter; } 140 set 141 { 142 System.Diagnostics.Debug.Assert(null != value, "clearing ValueSetter"); 143 // It doesn't matter which delegate wins, but only one should be jitted 144 Interlocked.CompareExchange(ref _memberSetter, value, null); 145 } 146 } 147 } 148 } 149