How do you get a web API odatamodelbuilder to work

2019-03-19 19:59发布

问题:

I have created a fairly simply domain model using pocos. I have mapped these to an EF DB context using EntityTypeConfiguration<TEnitityType> classes. This all works fine.

I am now trying to create an OData V4 WebAPI controller endpoint using a ODataConventionModelBuilder and this is where things are coming unstuck. It all works fine until it encounters an association that is not convention based. But I cannot find a way to get the ODataBuilder to pick up the mappings from my EntityTypeConfiguration<TEnitityType> classes.

This leaves my with 2 unpalatable options

  • Decorate my lovely clean pocos with dirty attributes.
  • Re-map all the non convention based mappings manually using the ODataBuilder

Not sure if code samples will help but here they are anyway, i have simplified the entities for brevity.

var builder = new ODataConventionModelBuilder();

            builder.EntitySet<Item>("Items");
            config.MapODataServiceRoute(
                routeName: "odata",
                routePrefix: "odata",
                model: builder.GetEdmModel(),
                batchHandler: new DefaultODataBatchHandler((GlobalConfiguration.DefaultServer)));

 public class Item
    {
        public Int32 Id { get; set; }

        public Int16 ItemTypeId { get; set; }                   

        public virtual ItemType Type { get; set; }
        public virtual ICollection<ItemVersion> Versions { get; set; }
        public virtual ICollection<ItemTag> Tags { get; set; }     
    }

The problem comes when it encounters the ItemTags collection, here is an ItemTag:

public class ItemTag
    {
        public Int32 ItemId { get; set; }

        public string Tag { get; set; }

        public Item Item { get; set; }
    }

Which you can see is not convention based and I have a configuration class for it as follows:

public class ItemTagConfiguration : EntityTypeConfiguration<ItemTag>
    {
        public ItemTagConfiguration()
        {
            HasKey(x => new {x.ItemId, x.Tag});

            HasRequired(x => x.Item)
                .WithMany(y => y.Tags)
                .HasForeignKey(x => x.ItemId);

        }
    }

Does anyone know of a way that I can use these EntityTypeConfiguration files with an ODataBuilder or web API?

EDIT

If found this page which seems to indicate it might be possible with EF 6 which I am using. What I want to do is this

ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Dbf>("Dbfs");
//            modelBuilder.Configurations.Add(new DbfMap());  <---- NO GOOD - Needs Class from DBContext we only have a model builder :(
Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "odata", model);

but the builder does not have a Configurations property.

回答1:

Two things:

  1. I have read multiple sources now that ward against using lazy loading and serialization; which is basically what OData is; (It even uses the system.runtime.serialization.datacontract and datamember attributes)

  2. I have had more success in explicitly loading from context, and defining navigation properties in the modelbuilder for dbContext. I understand you are looking at customized nav properties, but I am fairly sure these are overriden methods useful for the ODataModelBuilder class (that does not assume much and needs less Entity Framework to work). Where you mentioned using EF already, I imagine that is the direction you will work, and if you do not need to alias your model names, you add an entry for each Set, using convention naming.

    EntitySet("routePrefixName")

in building the EdmModel, and it wires up the relationships you made using Fluent previously. If you do have to add extraneous items to the underlying model, you should define each class as an EntityType<>(), only setting the key. EdmBuilder can use mild properties and key association to attach to the EF model in the ODataConventionModelBuilder.

I have wrestled and sought for some time, and there does not seem to be a wealth of information on .Net OData v4 floating around, probably due to the whole force datetimeoffset issue.

Hope that helps somewhat