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