c02df2400dc381ede4756fb1e62b36dfeba2a4e4
[mono.git] / mcs / class / referencesource / System.Web.Entity / System / Data / WebControls / EntityDataSourceMemberPath.cs
1 //---------------------------------------------------------------------
2 // <copyright file="EntityDataSourceMemberPath.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;
11 using System.Collections.Generic;
12 using System.Linq;
13 using System.Text;
14 using System.Data.EntityClient;
15 using System.Data.Metadata.Edm;
16 using System.Diagnostics;
17 using System.Globalization;
18 using System.Reflection;
19 using System.Data.Common;
20 using System.Data.Objects;
21
22 namespace System.Web.UI.WebControls
23 {
24     /// <summary>
25     /// A glorified linked list. Describes a chain of properties from a primitive
26     /// type to a root entity.
27     /// </summary>
28     class EntityDataSourceMemberPath
29     {
30         private readonly EdmProperty property;
31         private readonly PropertyInfo propertyInfo;
32         private readonly EntityDataSourceMemberPath parent;
33         private readonly bool isLocallyInteresting;
34         private readonly Type clrType;
35         private readonly bool isKey;
36
37         internal EntityDataSourceMemberPath(MetadataWorkspace ocWorkspace, EntityDataSourceMemberPath parent, EdmProperty property, bool isLocallyInteresting)
38         {
39             EntityDataSourceUtil.CheckArgumentNull(ocWorkspace, "ocWorkspace");
40             EntityDataSourceUtil.CheckArgumentNull(property, "property");
41             
42             this.property = property;
43             this.parent = parent;
44             this.isLocallyInteresting = isLocallyInteresting;
45             this.clrType = EntityDataSourceUtil.GetMemberClrType(ocWorkspace, property);
46             this.isKey = IsPropertyAKey(property);
47
48             // retrieve PropertyInfo (with respect to parent CLR type)
49             StructuralType parentType = property.DeclaringType;
50             Type parentClrType = EntityDataSourceUtil.GetClrType(ocWorkspace, parentType);
51
52             this.propertyInfo = EntityDataSourceUtil.GetPropertyInfo(parentClrType, this.property.Name);
53         }
54
55          /// <summary>
56         /// Describes the member path in the form 'property1.property2...'. Use to
57         /// determine display name for nested properties in the EDSC.
58         /// </summary>
59         /// <returns>Description of the </returns>
60         internal string GetDescription()
61         {
62             string prefix = null == this.parent ? string.Empty : this.parent.GetDescription() + ".";
63             return prefix + this.property.Name;
64         }
65
66         /// <summary>
67         /// Indicates whether original values of this member should be preserved.
68         /// </summary>
69         internal bool IsInteresting
70         {
71             get
72             {
73                 // a member path is interesting if anything along the path is interesting
74                 return this.isLocallyInteresting || (null != this.parent && this.parent.IsInteresting);
75             }
76         }
77
78         /// <summary>
79         /// Indicates whether this member represents a primary key value.
80         /// </summary>
81         internal bool IsKey
82         {
83             get { return this.isKey; }
84         }
85
86         /// <summary>
87         /// Indicates whether this member can be assigned a value of null.
88         /// </summary>
89         internal bool IsNullable
90         {
91             get { return this.property.Nullable; }
92         }
93
94         internal bool IsScalar
95         {
96             get { return EntityDataSourceUtil.IsScalar(this.property.TypeUsage.EdmType); }
97         }
98
99         /// <summary>
100         /// Gets the CLR type of the last member in the path.
101         /// </summary>
102         internal Type ClrType
103         {
104             get { return this.clrType; }
105         }
106
107         internal object GetValue(EntityDataSourceWrapper entity)
108         {
109             object parentObjectValue = GetParentObjectValue(entity, false /* initialize */); 
110             if (null == parentObjectValue)
111             {
112                 // use convention that property of null is null
113                 return null;
114             }
115             else
116             {
117                 // get this property
118                 object propertyValue = this.propertyInfo.GetValue(parentObjectValue, new object[] { });
119
120                 return propertyValue;
121             }
122         }
123
124         internal void SetValue(EntityDataSourceWrapper entity, object value)
125         {
126             object parentObjectValue = GetParentObjectValue(entity, true /* initialize */);
127
128             // set property value on parent
129             this.propertyInfo.SetValue(parentObjectValue, value, new object[] { });
130         }
131
132         private object Initialize(EntityDataSourceWrapper entity)
133         {
134             // get parent's value
135             object parentObjectValue = GetParentObjectValue(entity, true /* initialize */);
136
137             // construct type instance for this property
138             object propertyValue = EntityDataSourceUtil.InitializeType(this.ClrType);
139
140             // set property
141             this.propertyInfo.SetValue(parentObjectValue, propertyValue, new object[] { });
142
143             return propertyValue;
144         }
145
146         private object GetParentObjectValue(EntityDataSourceWrapper entity, bool initialize)
147         {
148             // get parent's value
149             object parentObjectValue;
150
151             if (null == this.parent)
152             {
153                 // at the top level, the entity is the value
154                 parentObjectValue = entity.WrappedEntity;
155             }
156             else
157             {
158                 parentObjectValue = this.parent.GetValue(entity);
159
160                 if (null == parentObjectValue && initialize)
161                 {
162                     parentObjectValue = this.parent.Initialize(entity);
163                 }
164             }
165
166             return parentObjectValue;
167         }
168
169         internal string GetEntitySqlValue()
170         {
171             // it.[member1].[member2]...
172             string prefix;
173
174             if (null != parent)
175             {
176                 prefix = parent.GetEntitySqlValue();
177             }
178             else
179             {
180                 prefix = EntityDataSourceUtil.EntitySqlElementAlias;
181             }
182
183             string eSql = prefix + "." + EntityDataSourceUtil.QuoteEntitySqlIdentifier(this.property.Name);
184
185             return eSql;
186         }
187
188         private bool IsPropertyAKey(EdmProperty property)
189         {
190             bool isKey = false;
191             EntityType entityType = property.DeclaringType as EntityType;
192             if (null != entityType)
193             {
194                 isKey = entityType.KeyMembers.Contains(property);
195             }
196             return isKey;
197         }
198
199         public override string ToString()
200         {
201             string prefix = null == this.parent ? string.Empty : this.parent.ToString() + "->";
202             return prefix + this.property.Name;
203         }
204     }
205 }