Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic properties with DerivesFrom is not working #2747

Open
komdil opened this issue Feb 11, 2023 · 2 comments
Open

Dynamic properties with DerivesFrom is not working #2747

komdil opened this issue Feb 11, 2023 · 2 comments
Assignees

Comments

@komdil
Copy link
Contributor

komdil commented Feb 11, 2023

I am having problem with a dynamic properties. It looks like it is not working with multiple inheritance. OData is not seeing dynamic properties from the base class.

Assemblies affected

Microsoft.AspNetCore.OData 8.0.11

Reproduce steps

Currently my model classes looks like this:

    public class Laptop : Product
    {
        public decimal Price { get; set; }
        public string Manufacturer { get; set; }
        public int Ram { get; set; }
        public string CPU { get; set; }
        public int HardDrive { get; set; }
    }

    public class ProductBase : ServerEntityBase
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }

    public class Product : ProductBase
    {
        public string Description { get; set; }
    }

    public abstract class ServerEntityBase
    {
        [NotMapped]
        public virtual IDictionary<string, object> Properties { get; set; }

        public ServerEntityBase()
        {

            Properties = new Dictionary<string, object>()
            {
                { "MySuperProperty","MySuperValue" }
            };
        }
    }

And my configuration:

        IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            ProductBaseMapping(builder);
            ProductMapping(builder);
            LaptopMapping(builder);
            return builder.GetEdmModel();
        }

        void ProductBaseMapping(ODataConventionModelBuilder builder)
        {
            builder.EntityType<ProductBase>();
            builder.EntitySet<ProductBase>("ProductBase");
        }

        void ProductMapping(ODataConventionModelBuilder builder)
        {
            builder.EntityType<Product>().DerivesFrom<ProductBase>();
            builder.EntitySet<Product>("Product");
        }

        void LaptopMapping(ODataConventionModelBuilder builder)
        {
            builder.EntityType<Laptop>().DerivesFrom<Product>();
            builder.EntitySet<Laptop>("Laptop");
        }

I am sending request for 3 routes:
https://localhost:7258/api/odata/productbase?$select=MySuperProperty
https://localhost:7258/api/odata/product?$select=MySuperProperty
https://localhost:7258/api/odata/laptop?$select=MySuperProperty

Expected result

I think it should work

Actual result

I am getting error: Could not find a property named 'MySuperProperty' on type [MyType]

@gathogojr
Copy link
Contributor

@komdil Thanks for reporting the issue. I'm investigating what could be going wrong when DerivesFrom method is used. Could you in the meantime just remove the lines with DerivesFrom? The inheritance will be resolved by the model builder even without that. If you remove the line, you should find that all the derived types will be marked with "OpenType"=True attribute in the service metadata and the $select expression will work as expected.

@gathogojr gathogojr self-assigned this Feb 15, 2023
@komdil
Copy link
Contributor Author

komdil commented Feb 16, 2023

@komdil Thanks for reporting the issue. I'm investigating what could be going wrong when DerivesFrom method is used. Could you in the meantime just remove the lines with DerivesFrom? The inheritance will be resolved by the model builder even without that. If you remove the line, you should find that all the derived types will be marked with "OpenType"=True attribute in the service metadata and the $select expression will work as expected.

You are right. I am using DerivesFrom for making workarounds with my base interface. I have an interface:

   public interface ISuperEntity
    {
        string Name { get; set; }
    }

This is a base interface of all classes. As you know OData does not support interfaces. I have a lot of places that I am using navigation property with that interface type. For example, SuperEntity property in my Laptop class. I am configuring all my classes with DerivesFrom and base class derives from this interface:

builder.EntityType<ServerEntityBase>().DerivesFrom<ISuperEntity>();

Then I can do $expand for this property. When I don;t use DerivesFrom it will show me exception:

Microsoft.OData.ODataException: The type 'ProductAPI.Model.Laptop' of a resource in an expanded link is not compatible with the element type 'ProductAPI.Model.ISuperEntity' of the expanded link. Entries in an expanded link must have entity types that are assignable to the element type of the expanded link.

Is there any difference between resolving inheritance by the model builder and by DerivesFrom? Should they work with the same behavior?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants