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); }