Exemplo n.º 1
0
        /* 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());
        }