1 //---------------------------------------------------------------------
2 // <copyright file="EdmProperty.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System.Data.Common;
11 using System.Threading;
13 namespace System.Data.Metadata.Edm
16 /// Represent the edm property class
18 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
19 public sealed class EdmProperty : EdmMember
23 /// Initializes a new instance of the property class
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>
29 internal EdmProperty(string name, TypeUsage typeUsage)
30 : base(name, typeUsage)
32 EntityUtil.CheckStringArgument(name, "name");
33 EntityUtil.GenericCheckArgumentNull(typeUsage, "typeUsage");
38 /// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary>
39 internal readonly System.RuntimeMethodHandle PropertyGetterHandle;
41 /// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary>
42 internal readonly System.RuntimeMethodHandle PropertySetterHandle;
44 /// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary>
45 internal readonly System.RuntimeTypeHandle EntityDeclaringType;
47 /// <summary>cached dynamic method to get the property value from a CLR instance</summary>
48 private Func<object,object> _memberGetter;
50 /// <summary>cached dynamic method to set a CLR property value on a CLR instance</summary>
51 private Action<object,object> _memberSetter;
55 /// Initializes a new OSpace instance of the property class
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>
61 internal EdmProperty(string name, TypeUsage typeUsage, System.Reflection.PropertyInfo propertyInfo, RuntimeTypeHandle entityDeclaringType)
62 : this(name, typeUsage)
64 System.Diagnostics.Debug.Assert(name == propertyInfo.Name, "different PropertyName");
65 if (null != propertyInfo)
67 System.Reflection.MethodInfo method;
69 method = propertyInfo.GetGetMethod(true); // return public or non-public getter
70 PropertyGetterHandle = ((null != method) ? method.MethodHandle : default(System.RuntimeMethodHandle));
72 method = propertyInfo.GetSetMethod(true); // return public or non-public getter
73 PropertySetterHandle = ((null != method) ? method.MethodHandle : default(System.RuntimeMethodHandle));
75 EntityDeclaringType = entityDeclaringType;
80 /// Returns the kind of the type
82 public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.EdmProperty; } }
85 /// Returns true if this property is nullable.
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.
104 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called when the EdmProperty instance is in ReadOnly state</exception>
109 return (bool)TypeUsage.Facets[DbProviderManifest.NullableFacetName].Value;
114 /// Returns the default value for this property
116 /// <exception cref="System.InvalidOperationException">Thrown if the setter is called when the EdmProperty instance is in ReadOnly state</exception>
117 public Object DefaultValue
121 return TypeUsage.Facets[DbProviderManifest.DefaultValueFacetName].Value;
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; }
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);
136 /// <summary>cached dynamic method to set a CLR property value on a CLR instance</summary>
137 internal Action<object,object> ValueSetter
139 get { return _memberSetter; }
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);