private void GenerateLists()
        {
            if (AttributeMetadataCache[LogicalName] == null)
            {
                throw new Exception("Failed to load metadata related to this entity.");
            }

            // choose non-primary attributes, and ones that don't represent others (like names of OptionSetValues)
            // sort by IsSelected, and then by name -- bubbles the selected to the top
            var attributes = from attributeQ in AttributeMetadataCache[LogicalName].Attributes
                             where (!attributeQ.IsPrimaryId.HasValue || !attributeQ.IsPrimaryId.Value) &&
                             string.IsNullOrEmpty(attributeQ.AttributeOf)
                             orderby EntityDataFilter.Attributes == null ||
                             EntityDataFilter.Attributes.Contains(attributeQ.LogicalName) descending,
                attributeQ.LogicalName
            select attributeQ;

            // if no filter, select all
            FieldsSelectAll = EntityDataFilter.Attributes != null &&
                              EntityDataFilter.Attributes.Length == attributes.Count();

            ReadOnlySelectAll = EntityDataFilter.ReadOnly != null &&
                                EntityDataFilter.ReadOnly.Length == attributes.Count();

            ClearFlagSelectAll = EntityDataFilter.ClearFlag != null &&
                                 EntityDataFilter.ClearFlag.Length == attributes.Count();

            foreach (var attribute in attributes)
            {
                var attributeAsync = attribute;

                Dispatcher.Invoke(() =>
                {
                    Fields.Add(new FieldGridRow
                    {
                        IsSelected =
                            EntityDataFilter.Attributes?.Contains(attributeAsync.LogicalName) == true,
                        Name        = attributeAsync.LogicalName,
                        DisplayName =
                            attributeAsync.DisplayName?.UserLocalizedLabel == null || !Settings.UseDisplayNames
                                                                                             ? Naming.GetProperVariableName(attributeAsync, Settings.TitleCaseLogicalNames)
                                                                                             : Naming.Clean(attributeAsync.DisplayName.UserLocalizedLabel.Label),
                        Rename =
                            EntityDataFilter.AttributeRenames?.FirstNotNullOrEmpty(attributeAsync.LogicalName),
                        Language =
                            EntityDataFilter.AttributeLanguages?.FirstNotNullOrEmpty(attributeAsync.LogicalName),
                        IsReadOnly = EntityDataFilter.ReadOnly?.Contains(attributeAsync.LogicalName) == true ||
                                     (attributeAsync.IsValidForCreate != true &&
                                      attributeAsync.IsValidForUpdate != true),
                        IsReadOnlyEnabled = attributeAsync.IsValidForCreate == true ||
                                            attributeAsync.IsValidForUpdate == true,
                        IsClearFlag =
                            EntityDataFilter.ClearFlag?.Contains(attributeAsync.LogicalName) == true
                    });
                });
            }

            var relations1N = from relation1nQ in AttributeMetadataCache[LogicalName].OneToManyRelationships
                              orderby EntityDataFilter.OneToN == null ||
                              EntityDataFilter.OneToN.Contains(relation1nQ.SchemaName) descending,
                relation1nQ.ReferencingEntity, relation1nQ.ReferencingAttribute
            select relation1nQ;

            // if no filter, select all
            Relations1NSelectAll = EntityDataFilter.OneToN != null &&
                                   EntityDataFilter.OneToN.Length == relations1N.Count();

            foreach (var relation1n in relations1N)
            {
                var relation1nAsync = relation1n;

                Dispatcher.Invoke(() =>
                {
                    var row = new Relations1NGridRow
                    {
                        IsSelected = EntityDataFilter.OneToN == null ||
                                     EntityDataFilter.OneToN.Contains(relation1nAsync.SchemaName),
                        Name     = relation1nAsync.SchemaName,
                        ToEntity = relation1nAsync.ReferencingEntity ?? "",
                        ToField  = relation1nAsync.ReferencingAttribute ?? "",
                        Rename   =
                            EntityDataFilter.OneToNRenames?.FirstNotNullOrEmpty(relation1nAsync.SchemaName),
                        IsReadOnlyEnabled = true,
                        IsReadOnly        = EntityDataFilter.OneToNReadOnly != null &&
                                            EntityDataFilter.OneToNReadOnly.ContainsKey(
                            relation1nAsync.SchemaName) &&
                                            EntityDataFilter.OneToNReadOnly[relation1nAsync.SchemaName]
                    };

                    Relations1N.Add(row);
                });
            }

            var relationsN1 = from relationN1Q in AttributeMetadataCache[LogicalName].ManyToOneRelationships
                              orderby EntityDataFilter.NToOne == null ||
                              EntityDataFilter.NToOne.Contains(relationN1Q.SchemaName) descending,
                relationN1Q.ReferencedEntity, relationN1Q.ReferencingAttribute
            select relationN1Q;

            // if no filter, select all
            RelationsN1SelectAll = EntityDataFilter.NToOne != null &&
                                   EntityDataFilter.NToOne.Length == relationsN1.Count();

            foreach (var relationN1 in relationsN1)
            {
                var relationN1Async = relationN1;

                Dispatcher.Invoke(() =>
                {
                    var row = new RelationsN1GridRow
                    {
                        IsSelected = EntityDataFilter.NToOne == null ||
                                     EntityDataFilter.NToOne.Contains(relationN1Async.SchemaName),
                        Name      = relationN1Async.SchemaName,
                        ToEntity  = relationN1Async.ReferencedEntity ?? "",
                        FromField = relationN1Async.ReferencingAttribute ?? "",
                        Rename    = EntityDataFilter.NToOneRenames?
                                    .FirstNotNullOrEmpty(relationN1Async.SchemaName),
                        IsFlatten = EntityDataFilter.NToOneFlatten != null &&
                                    EntityDataFilter.NToOneFlatten.ContainsKey(
                            relationN1Async.SchemaName) &&
                                    EntityDataFilter.NToOneFlatten[relationN1Async.SchemaName],
                        IsReadOnlyEnabled = true,
                        IsReadOnly        = EntityDataFilter.NToOneReadOnly != null &&
                                            EntityDataFilter.NToOneReadOnly.ContainsKey(
                            relationN1Async.SchemaName) &&
                                            EntityDataFilter.NToOneReadOnly[relationN1Async.SchemaName]
                    };

                    RelationsN1.Add(row);
                });
            }

            var relationsNN = from relationNNQ in AttributeMetadataCache[LogicalName].ManyToManyRelationships
                              orderby EntityDataFilter.NToN == null ||
                              EntityDataFilter.NToN.Contains(relationNNQ.SchemaName) descending,
            (relationNNQ.Entity1LogicalName == LogicalName)
                                                          ? relationNNQ.Entity2LogicalName
                                                          : (relationNNQ.Entity1LogicalName ?? ""),
            relationNNQ.IntersectEntityName
            select relationNNQ;

            // if no filter, select all
            RelationsNNSelectAll = EntityDataFilter.NToN != null &&
                                   EntityDataFilter.NToN.Length == relationsNN.Count();

            foreach (var relationNN in relationsNN)
            {
                var relationNNAsync = relationNN;

                Dispatcher.Invoke(() =>
                {
                    var row = new RelationsNNGridRow
                    {
                        IsSelected = EntityDataFilter.NToN == null ||
                                     EntityDataFilter.NToN.Contains(relationNNAsync.SchemaName),
                        Name     = relationNNAsync.SchemaName,
                        ToEntity = relationNNAsync.Entity1LogicalName == LogicalName
                                                                                               ? relationNNAsync.Entity2LogicalName
                                                                                               : (relationNNAsync.Entity1LogicalName ?? ""),
                        IntersectEntity   = relationNNAsync.IntersectEntityName ?? "",
                        Rename            = EntityDataFilter.NToNRenames?.FirstNotNullOrEmpty(relationNNAsync.SchemaName),
                        IsReadOnlyEnabled = true,
                        IsReadOnly        = EntityDataFilter.NToNReadOnly != null &&
                                            EntityDataFilter.NToNReadOnly.ContainsKey(
                            relationNNAsync.SchemaName) &&
                                            EntityDataFilter.NToNReadOnly[relationNNAsync.SchemaName]
                    };

                    RelationsNN.Add(row);
                });
            }
        }