/* Note Collections of optionals are not supported. */ protected ITypeInfo ResolveType(Type native, TNative member) { var isOptional = native.Name.ToLower().Contains("nullable") || native.Name.Contains("?") || native.HasAttribute <OptionalAttribute>() || member.HasAttribute <OptionalAttribute>(); if (isOptional) { native = native.GenericTypeArguments.Length > 0 ? native.GenericTypeArguments[0] : native; } IsOptional = isOptional; if (native != typeof(string)) { if (typeof(Stack).IsAssignableFrom(native)) { CollectionType = CollectionType.Stack; } else if (typeof(Queue).IsAssignableFrom(native)) { CollectionType = CollectionType.Queue; } else if (typeof(IDictionary).IsAssignableFrom(native)) { CollectionType = CollectionType.Dictionary; } else if (typeof(IEnumerable).IsAssignableFrom(native)) { CollectionType = CollectionType.Array; } if (CollectionType != CollectionType.None) { native = native.GenericTypeArguments[0]; } } return(MetadataProvider.Create(native)); }
public virtual void Configure(EntityTypeBuilder <T> builder) { if (!typeof(T).HasAttribute <ExportAttribute>()) { throw new Exception($"Type {typeof(T).Name} must contain an [Export] attribute to be configured here."); } var typeInfo = MetadataProvider.Create(typeof(T)); var properties = typeInfo .Properties .WithAttribute <DbPropertyAttribute>() .OrderBy(o => o.GetAttribute <DbPropertyAttribute>().Index) .ToList(); //MethodInfo propertyGenericMethod = null; properties.OfType <IPropertyInfo>().ForEach(p => { if (p.HasAttribute <DbReferenceAttribute>()) { var attr = p.GetAttribute <DbReferenceAttribute>(); if (p.CollectionType != CollectionType.None) { var collectionNavigationBuilder = builder.HasMany(p.Type.Native, p.Name); collectionNavigationBuilder.WithOne(); } else { var referenceNavigationBuilder = builder.HasOne(p.Type.Native, p.Name); if (attr.Multiplicity == DbReferenceMultiplicity.Many) { var manyBuilder = referenceNavigationBuilder.WithMany(); if (!p.IsOptional) { manyBuilder.IsRequired(); } } else if (attr.Multiplicity == DbReferenceMultiplicity.One) { var oneBuilder = referenceNavigationBuilder.WithOne(); if (!p.IsOptional) { oneBuilder.IsRequired(); } } } } else { var propertyTypeSupported = TypeMappingSource.FindMapping(p.Type.Native) != null; if (!propertyTypeSupported) { var referenceOwnershipBuilder = builder.OwnsOne(p.Type.Native, p.Name); // TODO: Optional, range //propertyBuilders.Add(builder.Property(p.Name)); //if (propertyGenericMethod == null) //{ // propertyGenericMethod = builder // .GetType() // .GetMethods(BindingFlags.Public | BindingFlags.Instance) // .FirstOrDefault(m => m.Name == "Property" && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string)); //} //var deconstructed = p.Deconstruct(); //if(deconstructed == null || !deconstructed.Any()) // throw new Exception($"Attempted to deconstruct unsupported type {p.GetPath()} but deconstruction failed."); //foreach (var d in deconstructed) //{ // var propertyConcreteMethod = propertyGenericMethod.MakeGenericMethod(d.Type.Native); // propertyConcreteMethod.Invoke(builder, new[] {d.Name}); //} } else { var propertyBuilder = builder.Property(p.Name); if (!p.IsOptional) { propertyBuilder.IsRequired(); } if (p.HasAttribute <RangeAttribute>() && p.Type.Native == typeof(string)) { var attr = p.GetAttribute <RangeAttribute>(); if (attr.HasMaximum()) { propertyBuilder.HasMaxLength(attr.GetMaximum <int>()); } } } } }); var keyProperties = properties.WithAttribute <DbKeyAttribute>().ToList(); if (!keyProperties.Any()) { throw new Exception($"Type {typeInfo.GetPath()} doesn't have any properties marked [DbKey]."); } builder.HasKey(keyProperties.Select(o => o.Name).ToArray()); }
public void Create_Returns_CSDL() { TestHelper.EnsureEDM(); var csdlDocument = MetadataProvider.Create(EntityDataModel.Current); Assert.Equal(@"<edmx:Edmx xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"" Version=""4.0""> <edmx:DataServices> <Schema xmlns=""http://docs.oasis-open.org/odata/ns/edm"" Namespace=""NorthwindModel""> <EnumType Name=""AccessLevel"" UnderlyingType=""Edm.Int32"" IsFlags=""True""> <Member Name=""None"" Value=""0"" /> <Member Name=""Read"" Value=""1"" /> <Member Name=""Write"" Value=""2"" /> <Member Name=""Delete"" Value=""4"" /> </EnumType> <EnumType Name=""Colour"" UnderlyingType=""Edm.Int32"" IsFlags=""False""> <Member Name=""Green"" Value=""1"" /> <Member Name=""Blue"" Value=""2"" /> <Member Name=""Red"" Value=""3"" /> </EnumType> <ComplexType Name=""OrderDetail""> <Property Name=""OrderId"" Type=""Edm.Int64"" Nullable=""false"" /> <Property Name=""ProductId"" Type=""Edm.Int32"" Nullable=""false"" /> <Property Name=""Quantity"" Type=""Edm.Int16"" Nullable=""false"" /> <Property Name=""UnitPrice"" Type=""Edm.Decimal"" Nullable=""false"" /> </ComplexType> <EntityType Name=""Categories""> <Key> <PropertyRef Name=""Name"" /> </Key> <Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" /> </EntityType> <EntityType Name=""Customers""> <Key> <PropertyRef Name=""CompanyName"" /> </Key> <Property Name=""City"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""CompanyName"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Country"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""LegacyId"" Type=""Edm.Int32"" Nullable=""false"" /> </EntityType> <EntityType Name=""Employees""> <Key> <PropertyRef Name=""Id"" /> </Key> <Property Name=""AccessLevel"" Type=""NorthwindModel.AccessLevel"" Nullable=""false"" /> <Property Name=""BirthDate"" Type=""Edm.Date"" Nullable=""false"" /> <Property Name=""EmailAddress"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Forename"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Id"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""ImageData"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Surname"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Title"" Type=""Edm.String"" Nullable=""false"" /> </EntityType> <EntityType Name=""Managers"" BaseType=""NorthwindModel.Employee""> <Property Name=""AnnualBudget"" Type=""Edm.Decimal"" Nullable=""false"" /> </EntityType> <EntityType Name=""Orders""> <Key> <PropertyRef Name=""OrderId"" /> </Key> <Property Name=""Freight"" Type=""Edm.Decimal"" Nullable=""false"" /> <Property Name=""OrderDetails"" Type=""Collection(NorthwindModel.OrderDetail)"" Nullable=""false"" /> <Property Name=""OrderId"" Type=""Edm.Int64"" Nullable=""false"" /> <Property Name=""ShipCountry"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""TransactionId"" Type=""Edm.Guid"" Nullable=""false"" /> </EntityType> <EntityType Name=""Products""> <Key> <PropertyRef Name=""ProductId"" /> </Key> <Property Name=""Category"" Type=""NorthwindModel.Category"" Nullable=""false"" /> <Property Name=""Colour"" Type=""NorthwindModel.Colour"" Nullable=""false"" /> <Property Name=""Deleted"" Type=""Edm.Boolean"" Nullable=""false"" /> <Property Name=""Description"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" /> <Property Name=""Price"" Type=""Edm.Decimal"" Nullable=""false"" /> <Property Name=""ProductId"" Type=""Edm.Int32"" Nullable=""false"" /> <Property Name=""Rating"" Type=""Edm.Int32"" Nullable=""false"" /> <Property Name=""ReleaseDate"" Type=""Edm.Date"" Nullable=""false"" /> </EntityType> <EntityContainer Name=""DefaultContainer""> <EntitySet Name=""Categories"" EntityType=""NorthwindModel.Category""> <Annotation Term=""Org.OData.Core.V1.ResourcePath"" String=""Categories"" /> <Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions""> <Record> <PropertyValue Property=""Insertable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions""> <Record> <PropertyValue Property=""Updatable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions""> <Record> <PropertyValue Property=""Deletable"" Bool=""True"" /> </Record> </Annotation> </EntitySet> <EntitySet Name=""Customers"" EntityType=""NorthwindModel.Customer""> <Annotation Term=""Org.OData.Core.V1.ResourcePath"" String=""Customers"" /> <Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions""> <Record> <PropertyValue Property=""Insertable"" Bool=""False"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions""> <Record> <PropertyValue Property=""Updatable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions""> <Record> <PropertyValue Property=""Deletable"" Bool=""False"" /> </Record> </Annotation> </EntitySet> <EntitySet Name=""Employees"" EntityType=""NorthwindModel.Employee""> <Annotation Term=""Org.OData.Core.V1.ResourcePath"" String=""Employees"" /> <Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions""> <Record> <PropertyValue Property=""Insertable"" Bool=""False"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions""> <Record> <PropertyValue Property=""Updatable"" Bool=""False"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions""> <Record> <PropertyValue Property=""Deletable"" Bool=""False"" /> </Record> </Annotation> </EntitySet> <EntitySet Name=""Managers"" EntityType=""NorthwindModel.Manager""> <Annotation Term=""Org.OData.Core.V1.ResourcePath"" String=""Managers"" /> <Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions""> <Record> <PropertyValue Property=""Insertable"" Bool=""False"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions""> <Record> <PropertyValue Property=""Updatable"" Bool=""False"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions""> <Record> <PropertyValue Property=""Deletable"" Bool=""False"" /> </Record> </Annotation> </EntitySet> <EntitySet Name=""Orders"" EntityType=""NorthwindModel.Order""> <Annotation Term=""Org.OData.Core.V1.ResourcePath"" String=""Orders"" /> <Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions""> <Record> <PropertyValue Property=""Insertable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions""> <Record> <PropertyValue Property=""Updatable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions""> <Record> <PropertyValue Property=""Deletable"" Bool=""True"" /> </Record> </Annotation> </EntitySet> <EntitySet Name=""Products"" EntityType=""NorthwindModel.Product""> <Annotation Term=""Org.OData.Core.V1.ResourcePath"" String=""Products"" /> <Annotation Term=""Org.OData.Capabilities.V1.InsertRestrictions""> <Record> <PropertyValue Property=""Insertable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.UpdateRestrictions""> <Record> <PropertyValue Property=""Updatable"" Bool=""True"" /> </Record> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.DeleteRestrictions""> <Record> <PropertyValue Property=""Deletable"" Bool=""True"" /> </Record> </Annotation> </EntitySet> </EntityContainer> <Annotations Target=""NorthwindModel.DefaultContainer""> <Annotation Term=""Org.OData.Capabilities.V1.DereferenceableIDs"" Bool=""true"" /> <Annotation Term=""Org.OData.Capabilities.V1.ConventionalIDs"" Bool=""true"" /> <Annotation Term=""Org.OData.Capabilities.V1.ConformanceLevel""> <EnumMember>Org.OData.Capabilities.V1.ConformanceLevelType/Minimal</EnumMember> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.SupportedFormats""> <Collection> <String>application/json;odata.metadata=none</String> <String>application/json;odata.metadata=minimal</String> </Collection> </Annotation> <Annotation Term=""Org.OData.Capabilities.V1.AsynchronousRequestsSupported"" Bool=""false"" /> <Annotation Term=""Org.OData.Capabilities.V1.BatchContinueOnErrorSupported"" Bool=""false"" /> <Annotation Term=""Org.OData.Capabilities.V1.FilterFunctions""> <Collection> <String>contains</String> <String>endswith</String> <String>startswith</String> <String>length</String> <String>indexof</String> <String>substring</String> <String>tolower</String> <String>toupper</String> <String>trim</String> <String>concat</String> <String>year</String> <String>month</String> <String>day</String> <String>hour</String> <String>second</String> <String>round</String> <String>floor</String> <String>ceiling</String> <String>cast</String> <String>isof</String> </Collection> </Annotation> </Annotations> </Schema> </edmx:DataServices> </edmx:Edmx>", csdlDocument.ToString()); }