Example #1
0
        private static Metadata Mapping(IEnumerable <EntityResource> entityResources, IEnumerable <EnumResource> enumResources, IEnumerable <GlobalItem> itemCollection, EntityContainer container)
        {
            if (itemCollection == null)
            {
                throw new ArgumentNullException(nameof(itemCollection));
            }

            var globalItems = itemCollection as IList <GlobalItem> ?? itemCollection.ToList();
            var retVal      = new Metadata(container.Name);

            // entity types
            foreach (var er in entityResources)
            {
                var fullName = $"{er.ClrType.FullName}, {er.ClrType.Assembly.GetName().Name}";
                var et       = new EntityType(fullName, er.Name)
                {
                    TableName = er.TableName
                };

                // entity informations
                if (er.Entity != null)
                {
                    et.QueryName = er.EntitySet.Name;
                    if (er.EntitySet.ElementType.Name != er.Name)
                    {
                        et.QueryType = er.EntitySet.ElementType.Name;
                    }
                    et.Keys.AddRange(er.Entity.KeyMembers.Select(k => k.Name));

                    // if entity has base type, set the base type's name
                    if (er.Entity.BaseType != null)
                    {
                        et.BaseTypeName = er.Entity.BaseType.Name;
                    }

                    if (er.ClrType != null)
                    {
                        et.ClrType = er.ClrType;
                    }

                    // navigation properties
                    if (er.NavigationProperties != null)
                    {
                        foreach (var p in er.NavigationProperties)
                        {
                            var ass = globalItems.OfType <AssociationType>().First(a => a.Name == p.RelationshipType.Name);
                            MetaUtils.GetDisplayInfo(er.ClrType, p.Name, out string resourceName, out Func <string> displayNameGetter);

                            var np = new NavigationProperty(p.Name, displayNameGetter)
                            {
                                ResourceName   = resourceName,
                                EntityTypeName = ((RefType)p.ToEndMember.TypeUsage.EdmType).ElementType.Name
                            };

                            if (p.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
                            {
                                np.IsScalar = true;
                                np.ForeignKeys.AddRange(ass.ReferentialConstraints.SelectMany(rc => rc.ToProperties.Select(tp => tp.Name)));
                            }
                            else
                            {
                                np.ForeignKeys.AddRange(ass.ReferentialConstraints.SelectMany(rc => rc.ToProperties.Select(tp => tp.Name)));
                            }

                            if (p.FromEndMember.DeleteBehavior == OperationAction.Cascade)
                            {
                                np.DoCascadeDelete = true;
                            }

                            if (er.ClrType != null)
                            {
                                MetaUtils.PopulateNavigationPropertyValidations(er.ClrType, np);
                            }

                            np.AssociationName = p.RelationshipType.Name;

                            et.NavigationProperties.Add(np);
                        }
                    }

                    // complex properties
                    if (er.ComplexProperties != null)
                    {
                        foreach (var p in er.ComplexProperties)
                        {
                            MetaUtils.GetDisplayInfo(er.ClrType, p.Key.Name,
                                                     out string resourceName,
                                                     out Func <string> displayNameGetter);

                            var cp = new ComplexProperty(p.Key.Name, displayNameGetter)
                            {
                                TypeName     = p.Key.TypeUsage.EdmType.Name,
                                ResourceName = resourceName,
                                Mappings     = p.Value
                            };

                            et.ComplexProperties.Add(cp);
                        }
                    }
                }
                else
                {
                    et.IsComplexType = true; // this is a complex type
                }

                // data properties
                foreach (var sp in er.SimpleProperties)
                {
                    var p       = sp.Value;
                    var clrType = UnderlyingClrType(p.TypeUsage.EdmType);
                    MetaUtils.GetDisplayInfo(er.ClrType, p.Name,
                                             out string resourceName, out Func <string> displayNameGetter);

                    var dp = new DataProperty(p.Name, displayNameGetter)
                    {
                        ColumnName   = sp.Key,
                        ResourceName = resourceName
                    };

                    var jsType = DataType.Binary;
                    if (p.TypeUsage.EdmType is EFEnumType enumType)
                    {
                        dp.IsEnum   = true;
                        dp.EnumType = enumType.Name;
                    }
                    else
                    {
                        // convert CLR type to javascript type
                        if (clrType == typeof(string))
                        {
                            jsType = DataType.String;
                        }
                        else if (clrType == typeof(Guid))
                        {
                            jsType = DataType.Guid;
                        }
                        else if (clrType == typeof(DateTime))
                        {
                            jsType = DataType.Date;
                        }
                        else if (clrType == typeof(DateTimeOffset))
                        {
                            jsType = DataType.DateTimeOffset;
                        }
                        else if (clrType == typeof(TimeSpan))
                        {
                            jsType = DataType.Time;
                        }
                        else if (clrType == typeof(bool))
                        {
                            jsType = DataType.Boolean;
                        }
                        else if (clrType == typeof(Int16) || clrType == typeof(Int64) || clrType == typeof(Int32))
                        {
                            jsType = DataType.Int;
                        }
                        else if (clrType == typeof(Single) || clrType == typeof(double) || clrType == typeof(decimal))
                        {
                            jsType = DataType.Number;
                        }
                        else if (clrType == typeof(byte))
                        {
                            jsType = DataType.Byte;
                        }
                        else if (clrType == typeof(DbGeography))
                        {
                            jsType = DataType.Geography;
                        }
                        else if (clrType == typeof(DbGeometry))
                        {
                            jsType = DataType.Geometry;
                        }
                        else if (clrType == typeof(byte[]))
                        {
                            jsType = DataType.Binary;
                        }
                        else
                        {
                            throw new BeetleException(Resources.UnknownDataType + p.TypeUsage.EdmType.Name);
                        }
                    }
                    dp.DataType = jsType;
                    var generated = p.MetadataProperties.FirstOrDefault(m => m.Name == StoreGeneratedPatternAttributeName);
                    if (generated == null)
                    {
                        dp.GenerationPattern = GenerationPattern.None;
                    }
                    else if (generated.Value.ToString().StartsWith("I"))
                    {
                        dp.GenerationPattern = GenerationPattern.Identity;
                    }
                    else
                    {
                        dp.GenerationPattern = GenerationPattern.Computed;
                    }

                    dp.UseForConcurrency = IsConcurrencyProperty(p);
                    if (p.Nullable)
                    {
                        dp.IsNullable = true;
                    }

                    if (jsType == DataType.Number)
                    {
                        var precision = GetPrecision(p);
                        if (precision.HasValue)
                        {
                            dp.Precision = precision;
                        }

                        var scale = GetScale(p);
                        if (scale.HasValue)
                        {
                            dp.Scale = scale;
                        }
                    }

                    if (er.ClrType != null)
                    {
                        MetaUtils.PopulateDataPropertyValidations(er.ClrType, dp, GetMaxStringLength(p));
                    }

                    if (p.DefaultValue != null)
                    {
                        dp.DefaultValue = p.DefaultValue;
                    }

                    et.DataProperties.Add(dp);
                }
                retVal.Entities.Add(et);
            }

            // enum types
            foreach (var enumResource in enumResources)
            {
                var enumType    = enumResource.EnumType;
                var enumClrType = enumResource.ClrType;
                var et          = new EnumType(enumType.Name);

                foreach (var member in enumType.Members)
                {
                    var enumMember = enumClrType.GetField(member.Name);
                    MetaUtils.GetDisplayInfo(enumMember, out string resourceName, out Func <string> displayNameGetter);
                    var em = new EnumMember(member.Name, displayNameGetter)
                    {
                        Value        = member.Value,
                        ResourceName = resourceName
                    };

                    et.Members.Add(em);
                }
                retVal.Enums.Add(et);
            }

            retVal.FixReferences();
            return(retVal);
        }
        public static Metadata Generate(IEnumerable <IEntityType> entityTypes)
        {
            if (entityTypes == null)
            {
                throw new ArgumentNullException(nameof(entityTypes));
            }

            var metadata = new Metadata();
            // entity types
            var entityTypeList = entityTypes as IList <IEntityType> ?? entityTypes.ToList();

            foreach (var entityType in entityTypeList)
            {
                var fullName  = $"{entityType.ClrType.FullName}, {entityType.ClrType.GetTypeInfo().Assembly.GetName().Name}";
                var tableName = entityType.GetAnnotations().FirstOrDefault(a => a.Name == "Relational:TableName")?.Value?.ToString();
                var et        = new EntityType(fullName, entityType.ClrType.Name)
                {
                    TableName = tableName
                };

                var keys = entityType.GetKeys().Where(k => k.IsPrimaryKey()).SelectMany(k => k.Properties.Select(p => p.Name));
                et.Keys.AddRange(keys);
                if (entityType.BaseType != null)
                {
                    et.BaseTypeName = entityType.BaseType.ClrType.Name;
                }

                et.ClrType = entityType.ClrType;

                foreach (var navigation in entityType.GetDeclaredNavigations())
                {
                    if (!navigation.TryGetMemberInfo(false, false, out MemberInfo memberInfo, out string _))
                    {
                        continue;
                    }

                    MetaUtils.GetDisplayInfo(memberInfo, out string resourceName, out Func <string> displayNameGetter);

                    var targetType = navigation.GetTargetType();
                    var np         = new NavigationProperty(navigation.Name, displayNameGetter)
                    {
                        ResourceName   = resourceName,
                        EntityTypeName = targetType.ClrType.Name,
                        IsScalar       = !navigation.IsCollection()
                    };

                    np.AssociationName = navigation.ForeignKey.DeclaringEntityType.ClrType.Name + "_" +
                                         navigation.ForeignKey.PrincipalEntityType.ClrType.Name + "_" +
                                         string.Join("+", np.ForeignKeys);

                    np.ForeignKeys.AddRange(navigation.ForeignKey.Properties.Select(p => p.Name));
                    np.DoCascadeDelete = navigation.ForeignKey.DeleteBehavior == DeleteBehavior.Cascade;

                    if (entityType.ClrType != null)
                    {
                        MetaUtils.PopulateNavigationPropertyValidations(memberInfo, np);
                    }

                    et.NavigationProperties.Add(np);
                }

                foreach (var property in entityType.GetDeclaredProperties())
                {
                    if (!property.TryGetMemberInfo(false, false, out MemberInfo memberInfo, out string _))
                    {
                        continue;
                    }

                    MetaUtils.GetDisplayInfo(memberInfo, out string resourceName, out Func <string> displayNameGetter);

                    var dp = new DataProperty(property.Name, displayNameGetter)
                    {
                        ColumnName   = property.FindAnnotation("Relational:ColumnName")?.Value.ToString(),
                        ResourceName = resourceName
                    };

                    var clrType = property.ClrType;
                    var jsType  = DataType.Binary;
                    // convert CLR type to javascript type
                    if (clrType.GetTypeInfo().IsEnum)
                    {
                        var enumType     = property.ClrType;
                        var enumTypeName = enumType.Name;
                        if (metadata.Enums.All(e => e.Name != enumTypeName))
                        {
                            metadata.Enums.Add(MetaUtils.GenerateEnumType(property.ClrType));
                        }
                        dp.IsEnum   = true;
                        dp.EnumType = enumTypeName;
                    }
                    else if (clrType == typeof(string))
                    {
                        jsType = DataType.String;
                    }
                    else if (clrType == typeof(Guid))
                    {
                        jsType = DataType.Guid;
                    }
                    else if (clrType == typeof(DateTime))
                    {
                        jsType = DataType.Date;
                    }
                    else if (clrType == typeof(DateTimeOffset))
                    {
                        jsType = DataType.DateTimeOffset;
                    }
                    else if (clrType == typeof(TimeSpan))
                    {
                        jsType = DataType.Time;
                    }
                    else if (clrType == typeof(bool))
                    {
                        jsType = DataType.Boolean;
                    }
                    else if (clrType == typeof(Int16) || clrType == typeof(Int64) || clrType == typeof(Int32))
                    {
                        jsType = DataType.Int;
                    }
                    else if (clrType == typeof(Single) || clrType == typeof(double) || clrType == typeof(decimal))
                    {
                        jsType = DataType.Number;
                    }
                    else if (clrType == typeof(byte))
                    {
                        jsType = DataType.Byte;
                    }
                    else if (clrType == typeof(byte[]))
                    {
                        jsType = DataType.Binary;
                    }

                    dp.DataType = jsType;
                    if (property.ValueGenerated == ValueGenerated.OnAdd)
                    {
                        dp.GenerationPattern = GenerationPattern.Identity;
                    }
                    else if (property.ValueGenerated == ValueGenerated.OnAddOrUpdate)
                    {
                        dp.GenerationPattern = GenerationPattern.Computed;
                    }

                    dp.UseForConcurrency = property.IsConcurrencyToken;
                    dp.IsNullable        = property.IsNullable;

                    MetaUtils.PopulateDataPropertyValidations(memberInfo, property.ClrType, dp);

                    et.DataProperties.Add(dp);
                }

                metadata.Entities.Add(et);
            }

            metadata.FixReferences();
            return(metadata);
        }