Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you get a web API odatamodelbuilder to work with EF fluent API mappings

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.

like image 422
Ben Robinson Avatar asked Jul 03 '14 15:07

Ben Robinson


People also ask

Does data annotation attributes override Fluent API configuration?

To write Fluent API configurations, override the OnModelCreating() method of DbContext in a context class, as shown below. You can use Data Annotation attributes and Fluent API at the same time. Entity Framework gives precedence to Fluent API over Data Annotations attributes.

Which of the following configuration activities Fluent API does?

Fluent API is another way to configure your domain classes. The Code First Fluent API is most commonly accessed by overriding the OnModelCreating method on your derived DbContext. Fluent API provides more functionality for configuration than DataAnnotations.

Which among the following is a Fluent API method that can be used to configure a default value?

Default Schema (EF6 onwards) Starting with EF6 you can use the HasDefaultSchema method on DbModelBuilder to specify the database schema to use for all tables, stored procedures, etc. This default setting will be overridden for any objects that you explicitly configure a different schema for.

Which of the following class is used as Fluent API in EF core?

In Entity Framework Core, the ModelBuilder class acts as a Fluent API. By using it, we can configure many different things, as it provides more configuration options than data annotation attributes.


1 Answers

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

like image 153
Nathan Teague Avatar answered Sep 26 '22 16:09

Nathan Teague