private IEnumerable <ReferenceKey> GetPossibleChildKeys(ReferenceMetadata parent)
        {
            IEnumerable <ReferenceKey> keys = parent.Properties.Value.SelectMany(a => a.Keys.Value);

            keys = keys.Concat(parent.Properties.Value.Where(m => m.Item != null).SelectMany(a => a.Item.Keys.Value));

            return(keys);
        }
        private IEnumerable <ReferenceMetadata> CreateProperties(IMetadataBuilderContext context, ReferenceMetadata parent)
        {
            foreach (IRelationMetadata attribute in parent.Relation.Properties)
            {
                ReferenceMetadata metadata = this.CreateBaseMetadata(context, attribute, parent);

                context.AddMetadata <IReferenceMetadata>(metadata);

                yield return(metadata);
            }
        }
        private ReferenceMetadata CreateItem(IMetadataBuilderContext context, ReferenceMetadata parent)
        {
            if (parent.Relation.Item != null)
            {
                ReferenceMetadata metadata = this.CreateBaseMetadata(context, parent.Relation.Item, parent);

                context.AddMetadata <IReferenceMetadata>(metadata);

                return(metadata);
            }

            return(null);
        }
 private IEnumerable <Reference> CreateChildReferences(ReferenceMetadata metadata)
 {
     foreach (Reference reference in this.GetPossibleParents(metadata).SelectMany(m => m.ParentReferences.Value))
     {
         if (reference.Metadata.Equals(metadata) && reference.HasFlag(ReferenceFlags.Self))
         {
             yield return(reference.Other);
         }
         else if (reference.Other.Metadata.Equals(metadata))
         {
             yield return(reference.Other);
         }
     }
 }
        private IEnumerable <ReferenceMetadata> GetPossibleParents(ReferenceMetadata metadata)
        {
            if (metadata.Parent != null)
            {
                yield return(metadata);

                yield return(metadata.Parent);

                if (metadata.Parent.HasFlag(RelationMetadataFlags.List) && metadata.Parent.Parent != null)
                {
                    yield return(metadata.Parent.Parent);
                }
            }
        }
        private ReferenceMetadata CreateBaseMetadata(IMetadataBuilderContext context, IRelationMetadata attribute, ReferenceMetadata parent)
        {
            ReferenceMetadata metadata = new ReferenceMetadata(attribute)
            {
                Parent = parent,
            };

            metadata.Flags            = this.CreateFlags(metadata);
            metadata.Properties       = this.CreateLazy(() => this.CreateProperties(context, metadata));
            metadata.Keys             = this.CreateLazy(() => this.CreateKeys(metadata));
            metadata.Item             = this.CreateItem(context, metadata);
            metadata.ParentReferences = this.CreateLazy(() => this.CreateParentReferences(metadata).ToList());
            metadata.ChildReferences  = this.CreateLazy(() => this.CreateChildReferences(metadata));

            return(metadata);
        }
Example #7
0
        private ReferenceMetadataFlags CreateFlags(ReferenceMetadata parent)
        {
            ReferenceMetadataFlags flags = ReferenceMetadataFlags.None;

            if (parent.Relation.Annotations.OfType <KeyAttribute>().Any())
            {
                flags |= ReferenceMetadataFlags.CandidateKey;
            }

            if (parent.Relation.Annotations.OfType <RefAttribute>().Any())
            {
                flags |= ReferenceMetadataFlags.ForeignKey;
            }

            return(flags);
        }
        private IEnumerable <ReferenceKey> CreateKeys(ReferenceMetadata parent)
        {
            if (this.IsNativeKeylessType(parent.Type))
            {
                return(Array.Empty <ReferenceKey>());
            }

            List <(ReferenceMetadata m, KeyAttribute a, string kn)>            keyMap = new List <(ReferenceMetadata, KeyAttribute, string)>();
            List <(ReferenceMetadata m, RefAttribute a, string rn, string kn)> refMap = new List <(ReferenceMetadata, RefAttribute, string, string)>();

            foreach (ReferenceMetadata property in parent.Properties.Value)
            {
                foreach (KeyAttribute keyAttr in property.Relation.Annotations.OfType <KeyAttribute>())
                {
                    string keyName = keyAttr.Name ?? property.Relation.Member?.Name ?? "";

                    keyMap.Add((property, keyAttr, keyName));
                }

                foreach (RefAttribute refAttr in property.Relation.Annotations.OfType <RefAttribute>())
                {
                    string refName = refAttr.Name;
                    string keyName = refAttr.Key ?? property.Relation.Member?.Name ?? "";

                    refMap.Add((property, refAttr, refName, keyName));
                }
            }

            IEnumerable <ReferenceKey> candidateKeys = keyMap.GroupBy(t => t.kn).Select(g => new ReferenceKey()
            {
                Type       = ReferenceKeyType.CandidateKey,
                Name       = g.First().kn,
                Properties = g.OrderBy(t => t.a.Index).Select(t => t.m).ToList(),
            });

            IEnumerable <ReferenceKey> foreignKeys = refMap.GroupBy(t => (t.rn, t.kn)).Select(g => new ReferenceKey()
            {
                Type       = ReferenceKeyType.ForeignKey,
                Name       = g.First().rn,
                Other      = g.First().kn,
                Properties = g.OrderBy(t => t.a.Index).Select(t => t.m).ToList(),
            });

            return(candidateKeys.Concat(foreignKeys));
        }
        private IEnumerable <Reference> CreateParentReferences(ReferenceMetadata parent)
        {
            if (!parent.Keys.Value.Any())
            {
                return(Array.Empty <Reference>());
            }

            IEnumerable <ReferenceKey> parentKeys = parent.Keys.Value;
            IEnumerable <ReferenceKey> childKeys  = this.GetPossibleChildKeys(parent);

            List <Reference> references = new List <Reference>();

            foreach (ReferenceKey parentKey in parentKeys)
            {
                foreach (ReferenceKey childKey in childKeys)
                {
                    if (this.IsKeyMatch(childKey, parentKey))
                    {
                        ReferenceMetadata childMetadata = childKey.Properties.First().Parent;

                        Reference rightRef = new Reference()
                        {
                            Metadata = childMetadata,
                            Flags    = ReferenceFlags.Child,
                            Key      = childKey,
                        };

                        Reference leftRef = new Reference()
                        {
                            Metadata = parent,
                            Flags    = ReferenceFlags.Parent | ReferenceFlags.One,
                            Key      = parentKey,
                        };

                        if (childKey.Type == ReferenceKeyType.CandidateKey)
                        {
                            rightRef.Flags |= ReferenceFlags.Primary;
                            leftRef.Flags  |= ReferenceFlags.Foreign;
                        }
                        else
                        {
                            rightRef.Flags |= ReferenceFlags.Foreign;
                            leftRef.Flags  |= ReferenceFlags.Primary;
                        }

                        if (childMetadata.Relation.HasFlag(RelationMetadataFlags.Item))
                        {
                            rightRef.Flags |= ReferenceFlags.Many;
                            rightRef.List   = leftRef.List = childMetadata.Parent;
                        }
                        else
                        {
                            rightRef.Flags |= ReferenceFlags.One;
                        }

                        leftRef.Other  = rightRef;
                        rightRef.Other = leftRef;

                        references.Add(leftRef);
                    }
                }
            }


            foreach (Reference reference in references.ToList())
            {
                Reference other = references.Except(new[] { reference }).FirstOrDefault(r => r.Other.Key.Equals(reference.Key));

                if (other != null && this.IsPreferredParentForSelfJoin(reference, other))
                {
                    if (reference.Other.Metadata.Relation.HasFlag(RelationMetadataFlags.Recursive))
                    {
                        reference.Flags       |= ReferenceFlags.Self;
                        reference.Other.Flags |= ReferenceFlags.Self;
                        reference.Other.Key    = other.Key;
                    }

                    references.Remove(other);
                }
            }

            return(references);
        }