File: EntityDataSourceDataSelection.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (651 lines) | stat: -rw-r--r-- 29,535 bytes parent folder | download
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
//------------------------------------------------------------------------------
// <copyright file="EntityDataSourceDataSelection.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner       [....]
// @backupOwner [....]
//
// Manages the properties that can be set on the second page of the wizard
//------------------------------------------------------------------------------

namespace System.Web.UI.Design.WebControls
{
    using System.Collections.Generic;
    using System.Data.Metadata.Edm;
    using System.Diagnostics;
    using System.Globalization;
    using System.Text;

    internal class EntityDataSourceDataSelection
    {
        #region Private static fields
        // iterator prefix used in building and parsing Select property value
        private static readonly string s_itKeyword = "it.";
        // Placeholder item to indicate (None) on the EntityTypeFilter ComboBox
        private static readonly EntityDataSourceEntityTypeFilterItem s_entityTypeFilterNoneItem =
                new EntityDataSourceEntityTypeFilterItem(Strings.Wizard_DataSelectionPanel_NoEntityTypeFilter);
        #endregion

        #region Private readonly fields
        private readonly EntityDataSourceDataSelectionPanel _panel;
        private readonly EntityDataSourceDesignerHelper _helper;
        #endregion

        #region Private fields for temporary storage of property values
        private readonly EntityDataSourceState _entityDataSourceState;
        private List<EntityDataSourceEntitySetNameItem> _entitySetNames;
        private EntityDataSourceEntitySetNameItem _selectedEntitySetName;
        private List<EntityDataSourceEntityTypeFilterItem> _entityTypeFilters;
        private EntityDataSourceEntityTypeFilterItem _selectedEntityTypeFilter;

        #region Select views
        // The Data Selection wizard panel can display two kinds of views of the Select property:
        //     (1) Simple Select View: CheckedListBox with a list of available entity type properties
        //     (2) Advanced Select View: TextBox that allows any statement to be entered (no validation)
        //
        // When either view is visible to the user, the fields shown below for that view should be non-null, and the fields
        // for the other view should be null.

        // Simple Select View
        // _selectedEntityTypeProperties contains a set of indexes of properties in _entityTypeProperties
        private List<string> _entityTypeProperties; 
        private List<int> _selectedEntityTypeProperties;

        // Advanced Select View
        private string _select;
        #endregion

        private bool _enableInsert;
        private bool _enableUpdate;
        private bool _enableDelete;
        private readonly EntityDataSourceWizardForm _wizardForm;        
        #endregion

        #region Constructors
        internal EntityDataSourceDataSelection(EntityDataSourceDataSelectionPanel panel, EntityDataSourceWizardForm wizard, EntityDataSourceDesignerHelper designerHelper, EntityDataSourceState entityDataSourceState)
        {
            _panel = panel;
            _panel.Register(this);
            _helper = designerHelper;

            _entityDataSourceState = entityDataSourceState;
            _wizardForm = wizard;
        }
        #endregion

        #region Events
        // Event handler to process notifications when a DefaultContainerName is selected on the ObjectContext configuration panel
        internal void ContainerNameChangedHandler(object sender, EntityDataSourceContainerNameItem newContainerName)
        {
            // Load the entity sets for this container, don't select anything initially in the list
            LoadEntitySetNames(newContainerName, null);
            
            // Reset the other controls that depend on the value of EntitySet
            LoadEntityTypeFilters(null, null);
            LoadSelect(String.Empty);
        }
        #endregion        

        #region Methods to manage temporary state and wizard contents
        // Used when the wizard is launched, to load existing property values from data source control
        internal void LoadState()
        {
            LoadEntitySetNames(_helper.GetEntityContainerItem(_entityDataSourceState.DefaultContainerName), _entityDataSourceState.EntitySetName);
            LoadEntityTypeFilters(_selectedEntitySetName, _entityDataSourceState.EntityTypeFilter);
            LoadSelect(_entityDataSourceState.Select);
            LoadInsertUpdateDelete();
        }

        // Save current wizard settings back to the EntityDataSourceState
        internal void SaveState()
        {
            SaveEntitySetName();
            SaveEntityTypeFilter();
            SaveSelect();
            SaveInsertUpdateDelete();
            SaveEnableFlattening();
        }

        #region EntitySetName
        // Find the specified entitySetName in the list or add it if it's not there
        private EntityDataSourceEntitySetNameItem FindEntitySetName(string entitySetName)
        {
            if (!String.IsNullOrEmpty(entitySetName))
            {
                EntityDataSourceEntitySetNameItem entitySetToSelect = null;
                foreach (EntityDataSourceEntitySetNameItem entitySetNameItem in _entitySetNames)
                {
                    // Ignore case here when searching the list for a matching item, but set the temporary state property to the
                    // correctly-cased version from metadata so that if the user clicks Finish, the correct one will be saved. This
                    // allows some flexibility the designer without preserving an incorrectly-cased value that could cause errors at runtime.                    
                    if (String.Equals(entitySetNameItem.EntitySetName, entitySetName, StringComparison.OrdinalIgnoreCase))
                    {
                        entitySetToSelect = entitySetNameItem;
                    }
                }

                // didn't find a matching entityset, so just create a placeholder for one using the specified name and add it to the list
                if (entitySetToSelect == null)
                {
                    entitySetToSelect = new EntityDataSourceEntitySetNameItem(entitySetName);
                    _entitySetNames.Add(entitySetToSelect);                    
                }

                Debug.Assert(entitySetToSelect != null, "expected a non-null EntityDataSourceEntitySetNameItem");
                return entitySetToSelect;
            }

            return null;
        }

        // Populates the EntitySetName combobox with all of the discoverable EntitySets for the specified container.
        // If the specified entitySetName is not empty, it is added to the list and selected as the initial value
        // containerNameItem may not be backed by a real EntityContainer, in which case there is no way to look up the EntitySet in metadata
        // devnote: This method should not automatically reset EntityTypeFilter and Select because it can be used to load the initial state
        //          for the form, in which case we need to preserve any values that are already set on the data source control.
        private void LoadEntitySetNames(EntityDataSourceContainerNameItem containerNameItem, string entitySetName)
        {
            // If this is a container that we found in the project's metadata, get a list of EntitySets for that container
            if (containerNameItem != null && containerNameItem.EntityContainer != null)
            {
                _entitySetNames = _helper.GetEntitySets(containerNameItem.EntityContainer, false /*sortResults*/);

                // Try to find the specified entityset in list and add it if it isn't there
                _selectedEntitySetName = FindEntitySetName(entitySetName);
            }
            else
            {
                // if this is an unknown container, there is no way to find a list of entitysets from metadata
                // so just create a new list and placeholder for the specified entityset
                _entitySetNames = new List<EntityDataSourceEntitySetNameItem>();
                if (!String.IsNullOrEmpty(entitySetName))
                {
                    _selectedEntitySetName = new EntityDataSourceEntitySetNameItem(entitySetName);
                    _entitySetNames.Add(_selectedEntitySetName);
                }
                else
                {
                    _selectedEntitySetName = null;
                }
            }

            // Sort the list now, after we may have added one above
            _entitySetNames.Sort();

            // Update the controls
            _panel.SetEntitySetNames(_entitySetNames);
            _panel.SetSelectedEntitySetName(_selectedEntitySetName);
        }

        // Set EntitySetName in temporary storage
        internal void SelectEntitySetName(EntityDataSourceEntitySetNameItem selectedEntitySet)
        {
            _selectedEntitySetName = selectedEntitySet;
            // Load the types for the selected EntitySet, don't select one initially
            LoadEntityTypeFilters(selectedEntitySet, null);
            // Reinitialize the Select control with a list of properties, don't preserve any existing Select value
            LoadSelect(String.Empty);
        }

        private void SaveEntitySetName()
        {
            if (_selectedEntitySetName != null)
            {
                _entityDataSourceState.EntitySetName = _selectedEntitySetName.EntitySetName;
            }
            else
            {
                _entityDataSourceState.EntitySetName = String.Empty;
            }
        }
        #endregion

        #region EntityTypeFilter
        // Populate a list with the base type for the EntitySet plus all derived types, and a special entry to indicate no filter
        // devnote: This method should not automatically reset Select because it can be used to load the initial state
        //          for the form, in which case we need to preserve any values that are already set on the data source control.
        private void LoadEntityTypeFilters(EntityDataSourceEntitySetNameItem entitySetItem, string entityTypeFilter)
        {
            // If this is an EntitySet that we found in the project's metadata, get the type information
            if (entitySetItem != null && entitySetItem.EntitySet != null)
            {
                _entityTypeFilters = _helper.GetEntityTypeFilters(entitySetItem.EntitySet.ElementType, false /*sortResults*/);
                // add (None) to the beginning of the list
                _entityTypeFilters.Insert(0, s_entityTypeFilterNoneItem);

                // Try to find the specified type in list and add it if it isn't there
                _selectedEntityTypeFilter = FindEntityTypeFilter(entityTypeFilter);
            }
            else
            {
                // if this is an unknown EntitySet, there is no way to find a list of types from metadata
                // so just create a new list and placeholder for the specified type
                _entityTypeFilters = new List<EntityDataSourceEntityTypeFilterItem>();
                _entityTypeFilters.Add(s_entityTypeFilterNoneItem);

                if (!String.IsNullOrEmpty(entityTypeFilter))
                {
                    _selectedEntityTypeFilter = new EntityDataSourceEntityTypeFilterItem(entityTypeFilter);
                    _entityTypeFilters.Add(_selectedEntityTypeFilter);
                }
                else
                {
                    _selectedEntityTypeFilter = s_entityTypeFilterNoneItem;
                }
            }

            // Sort now after we might have added items above
            _entityTypeFilters.Sort();

            // Update the controls
            _panel.SetEntityTypeFilters(_entityTypeFilters);
            _panel.SetSelectedEntityTypeFilter(_selectedEntityTypeFilter);
        }

        // Find the specified entityTypeFilter in the list and add it if it's not there
        private EntityDataSourceEntityTypeFilterItem FindEntityTypeFilter(string entityTypeFilter)
        {
            if (!String.IsNullOrEmpty(entityTypeFilter))
            {
                EntityDataSourceEntityTypeFilterItem typeToSelect = null;
                foreach (EntityDataSourceEntityTypeFilterItem entityTypeFilterItem in _entityTypeFilters)
                {
                    // Ignore case here when searching the list for a matching item, but set the temporary state property to the
                    // correctly-cased version from metadata so that if the user clicks Finish, the correct one will be saved. This
                    // allows some flexibility the designer without preserving an incorrectly-cased value that could cause errors at runtime.                    
                    if (String.Equals(entityTypeFilterItem.EntityTypeName, entityTypeFilter, StringComparison.OrdinalIgnoreCase))
                    {
                        typeToSelect = entityTypeFilterItem;
                    }
                }

                // didn't find a matching type, so just create a placeholder item and add it to the list
                if (typeToSelect == null)
                {
                    typeToSelect = new EntityDataSourceEntityTypeFilterItem(entityTypeFilter);
                    _entityTypeFilters.Add(typeToSelect);

                }

                Debug.Assert(typeToSelect != null, "expected a non-null string for EntityTypeFilter");
                return typeToSelect;
            }

            return s_entityTypeFilterNoneItem;
        }

        // Set EntityTypeFilter in temporary storage and load the Select property
        internal void SelectEntityTypeFilter(EntityDataSourceEntityTypeFilterItem selectedEntityTypeFilter)
        {
            _selectedEntityTypeFilter = selectedEntityTypeFilter;
            // Reinitialize the Select control with a list of properties, don't preserve any existing Select value
            LoadSelect(String.Empty);
        }

        private void SaveEntityTypeFilter()
        {
            // If (None) is selected, it is the same as an empty string on the data source control
            if (Object.ReferenceEquals(_selectedEntityTypeFilter, s_entityTypeFilterNoneItem))
            {
                _entityDataSourceState.EntityTypeFilter = String.Empty;
            }
            else
            {
                _entityDataSourceState.EntityTypeFilter = _selectedEntityTypeFilter.EntityTypeName;
            }
        }

        #endregion

        #region Select
        // Load and parse the Select property
        private void LoadSelect(string select)
        {
            Debug.Assert(_selectedEntityTypeFilter != null, "_selectedEntityTypeFilter should never be null");

            EntityType entityType = GetSelectedEntityType();

            if (entityType != null)
            {
                // this is a real type from metadata, load its properties
                _entityTypeProperties = _helper.GetEntityTypeProperties(entityType);
                // add the 'Select All (Entity Value)' placeholder at the beginning of the list
                _entityTypeProperties.Insert(0, Strings.Wizard_DataSelectionPanel_SelectAllProperties);

                // parse the current value for the Select property to see if it can be displayed in the simple CheckedListBox view                
                if (TryParseSelect(select))
                {
                    _select = null;

                    // Update the controls
                    _panel.SetEntityTypeProperties(_entityTypeProperties, _selectedEntityTypeProperties);
                    UpdateInsertUpdateDeleteState();
                    return;
                }
                // else we failed to parse the select into entity type properties on the specified type, so just use the advanced select view
            } // else can't get a list of properties unless we have a known EntityType


            // if we don't have a valid entity type or couldn't parse the incoming Select value, just display the advanced TextBox view
            _entityTypeProperties = null;
            _selectedEntityTypeProperties = null;
            _select = select;

            // Update the controls
            _panel.SetSelect(_select);
            UpdateInsertUpdateDeleteState();
        }

        // Build a value for the Select property from the selected values in the CheckedListBox
        // Value will be in the from "it.Property1, it.Property2, it.Property3"
        private string BuildSelect()
        {
            Debug.Assert(_selectedEntityTypeProperties != null && _selectedEntityTypeProperties.Count > 0, "expected non-null _selectedEntityTypeProperties with at least one value");

            // 'Select All (Entity Value)' is the same thing as an empty string for the property
            if (_selectedEntityTypeProperties[0] == 0)
            {
                Debug.Assert(_selectedEntityTypeProperties.Count == 1, "'Select All (Entity Value)' should be the only property selected");
                return String.Empty;
            }

            StringBuilder selectProperties = new StringBuilder();
            bool addComma = false;
            foreach (int propertyIndex in _selectedEntityTypeProperties)
            {
                if (addComma)
                {
                    selectProperties.Append(", ");
                }
                else
                {
                    addComma = true;
                }

                selectProperties.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", s_itKeyword, EscapePropertyName(_entityTypeProperties[propertyIndex]));

            }
            return selectProperties.ToString();
        }

        private static string EscapePropertyName(string propertyName)
        {
            return "[" + propertyName.Replace("]", "]]") + "]";
        }

        static string UnescapePropertyName(string name)
        {
            if (name[0] == '[' && name[name.Length - 1] == ']')
            {
                return name.Substring(1, name.Length - 2).Replace("]]", "]");
            }
            else
            {
                // else the property is not escaped at all or is not properly escaped. We can't parse it so just return.
                return name;
            }            
        }

        // Parses the current Select property on the data source to see if it matches a specific format that we can use to display the properties
        // in the CheckedListBox in the simple select wizard view
        private bool TryParseSelect(string currentSelect)
        {
            bool parseSuccess = false; // gets set to true after the statement has been successfully parsed
            if (!String.IsNullOrEmpty(currentSelect))
            {
                // first try to split the string up into pieces divided by commas
                // expects a format like the following: (extra spaces around the commas should work as well)
                //     "it.KnownPropertyName1, it.KnownPropertyName2, it.KnownPropertyName3"                
                string[] tokenizedSelect = currentSelect.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                bool foundUnknownProperty = false;
                List<int> selectedProperties = new List<int>();
                foreach (string token in tokenizedSelect)
                {
                    string propertyName = token.Trim();

                    // Does the current property token start with "it."?
                    if (ReadItKeyword(propertyName))
                    {
                        // Does the rest of the property token match a known property name for the selected EntityTypeFilter?
                        int propertyIndex = ReadPropertyName(propertyName.Substring(s_itKeyword.Length));
                        if (propertyIndex == -1)
                        {
                            // the property was not known, so we can just stop looking
                            foundUnknownProperty = true;
                            break;
                        }
                        else
                        {
                            // this is a known property, so add its index to the list
                            selectedProperties.Add(propertyIndex);
                        }
                    }
                    else
                    {
                        // the property was not known, so we can just stop looking
                        foundUnknownProperty = true;
                        break;
                    }
                }
                if (!foundUnknownProperty)
                {
                    // if we never found anything unknown, the current list of properties is what we'll use to fill in the CheckedListBox
                    _selectedEntityTypeProperties = selectedProperties;
                    parseSuccess = true;
                }
                else
                {
                    _selectedEntityTypeProperties = null;
                }
            }
            else
            {
                // if Select is empty, we just want to add 'Select All (Entity Value)' to the list
                _selectedEntityTypeProperties = new List<int>();
                _selectedEntityTypeProperties.Add(0);
                parseSuccess = true;
            }

            return parseSuccess;
        }

        // Determines if the specified propertyName starts with "it." (case-insensitive)
        private bool ReadItKeyword(string propertyName)
        {
            // will accept any casing of "it." here, although when the value is saved back to the property, it will be correctly lower-cased
            return propertyName.StartsWith(s_itKeyword, StringComparison.OrdinalIgnoreCase);
        }

        // Determines if the specified propertyName matches one of the known properties for the selected type
        private int ReadPropertyName(string propertyName)
        {
            for (int propIndex = 0; propIndex < _entityTypeProperties.Count; propIndex++)
            {
                // Ignore case here when searching the list for a matching item, but set the temporary state property to the
                // correctly-cased version from metadata so that if the user clicks Finish, the correct one will be saved. This
                // allows some flexibility the designer without preserving an incorrectly-cased value that could cause errors at runtime.

                // Does the specified property name exactly match any of the properties for the selected EntityTypeFilter?
                if (String.Equals(UnescapePropertyName(propertyName), _entityTypeProperties[propIndex], StringComparison.OrdinalIgnoreCase))
                {
                    return propIndex;
                }
            }

            return -1;
        }

        // Add the specified property to the list of selected entity properties used to build up the Select property
        internal void SelectEntityProperty(int propertyIndex)
        {
            _selectedEntityTypeProperties.Add(propertyIndex);
        }

        internal void ClearAllSelectedProperties()
        {
            _selectedEntityTypeProperties.Clear();
        }

        // Remove specified entity property index from the selected list
        internal void DeselectEntityProperty(int propertyIndex)
        {
            _selectedEntityTypeProperties.Remove(propertyIndex);
        }

        // Set Select property to the specified string (used with advanced select view)
        internal void SelectAdvancedSelect(string select)
        {
            _select = select;
        }

        private void SaveSelect()
        {
            if (_select != null)
            {
                _entityDataSourceState.Select = _select;
            }
            else
            {
                Debug.Assert(_selectedEntityTypeProperties != null, "expected _entityTypeProperties to be non-null if _select is null");
                _entityDataSourceState.Select = BuildSelect();
            }
        }
        #endregion

        #region EnableInsertUpdateDelete
        // Load the initial values for EnableInsert/EnableUpdate/EnableDelete CheckBoxes
        private void LoadInsertUpdateDelete()
        {
            SelectEnableInsert(_entityDataSourceState.EnableInsert);
            SelectEnableUpdate(_entityDataSourceState.EnableUpdate);
            SelectEnableDelete(_entityDataSourceState.EnableDelete);

            UpdateInsertUpdateDeleteState();
        }

        // Set EnableDelete in temporary storage
        internal void SelectEnableDelete(bool enableDelete)
        {
            _enableDelete = enableDelete;
        }

        // Set EnableInsert in temporary storage
        internal void SelectEnableInsert(bool enableInsert)
        {
            _enableInsert = enableInsert;
        }

        // Set EnableUpdate in temporary storage
        internal void SelectEnableUpdate(bool enableUpdate)
        {
            _enableUpdate = enableUpdate;
        }

        private void SaveInsertUpdateDelete()
        {
            _entityDataSourceState.EnableInsert = _enableInsert;
            _entityDataSourceState.EnableUpdate = _enableUpdate;
            _entityDataSourceState.EnableDelete = _enableDelete;
        }

        /// <summary>
        /// Update the panel control state based on the valued of enableInsert,
        /// enableUpdate, enableDelete, and the selectedEntityTypeProperties
        /// </summary>
        internal void UpdateInsertUpdateDeleteState()
        {
            // Set the checkbox state for the panel controls
            _panel.SetEnableInsertUpdateDelete(_enableInsert, _enableUpdate, _enableDelete);

            // The InsertUpdateDelete panel should be enabled if:
            // 1. Insert, Update, or Delete is selected -OR-
            // 2. The EntitySelection has SelectAll checked
            bool enablePanel = (_enableInsert || _enableUpdate || _enableDelete || 
                        (_selectedEntityTypeProperties != null && 
                         _selectedEntityTypeProperties.Count == 1 && 
                         _selectedEntityTypeProperties[0] == 0));

            _panel.SetEnableInsertUpdateDeletePanel(enablePanel);
        }
        #endregion        

        #region  EnableFlattening

        private EntityType GetSelectedEntityType()
        {
            EntityType entityType = null;

            // determine which EntityType to load properties for, based on the value selected for EntityTypeFilter
            if (Object.ReferenceEquals(_selectedEntityTypeFilter, s_entityTypeFilterNoneItem))
            {
                // If (None) is selected, use the base type for the EntitySet if available
                if (_selectedEntitySetName != null && _selectedEntitySetName.EntitySet != null)
                {
                    entityType = _selectedEntitySetName.EntitySet.ElementType;
                }
                // else the EntitySet base type is not known
            }
            else
            {
                entityType = _selectedEntityTypeFilter.EntityType; // could still be null if the type if not known in metadata
            }

            return entityType;
        }

        private void SaveEnableFlattening()
        {
            bool enableFlattening = false;

            EntityType entityType = GetSelectedEntityType();

            if (entityType != null)
            {
                foreach (EdmMember member in entityType.Members)
                {
                    // If there is a complex member, enable flattening
                    if (member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                    {
                        enableFlattening = true;
                        break;
                    }
                    else if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
                    {
                        NavigationProperty navProp = (NavigationProperty)member;
                        if (navProp.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
                        {
                            AssociationType associationType = navProp.ToEndMember.DeclaringType as AssociationType;
                            if (!associationType.IsForeignKey)
                            {
                                // If there is an independent association, enable flattening
                                enableFlattening = true;
                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                // Projection
                enableFlattening = true;
            }

            _entityDataSourceState.EnableFlattening = enableFlattening;
        }

        #endregion

        #endregion

        #region Wizard button state management
        internal void UpdateWizardState()
        {
            // EntitySetName must be selected and a Select must be configured or must be the empty string
            _wizardForm.SetCanFinish(_selectedEntitySetName != null && (_select != null || _selectedEntityTypeProperties.Count > 0));
        }
        #endregion
    }
}