Search code examples
c#asp.net-web-apiodatabreeze

ODataConventionModelBuilder with inherited entities


I've an WebAPI OData v3 interface using ODataConventionModelBuilder. It contains some entities which are inherited, and also a model which has a collection of the abstract object:

public abstract class BaseObject
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("Object3")]
    public int? ParentId { get; set; }

    public virtual Object3 Parent { get; set; }
}

public class Object1: BaseObject
{
}

public class Object2: BaseObject
{
}

public class Object3
{
    [Key]
    public int Id { get; set; }

    public ICollection<BaseObject> MyObjects { get; set; }
}

I'm calling the interface using Breeze with client side metadata, using expand:

http://example.com/api/Object3?$expand=MyObjects

The server response looks like this:

{
    "odata.type":"MyNamespace.Object1",
    "odata.id":"http://example.com/api/BaseObject(1)",
    "[email protected]":"http://example.com/api/BaseObject(1)/Parent",
    "Id":1,
    "ParentId":1
}

Breeze now recognizes this as an entity of type Object1. But if I modify the entity and save the changes it makes a POST request to http://example.com/api/BaseObject(1). To being able to handle the different concrete types I need the POST request to go to the specific controller http://example.com/api/Object(1).

What do I need to change so that Breeze makes to update POST calls to the concrete controller and not the controller of the base object?

UPDATE: After inspecting the Breeze source code, it seems like Breeze uses the odata.id as URI for the POST request. Is it somehow possible to have the OData API return the URI for the concrete object as odata.id instead of the base object?


Solution

  • I got this working with a nasty hack by removing extraMetadata from all entities before saving with breeze:

    var entities = manager.getEntities(null, breeze.EntityState.Modified);
    for (var i = 0; i < entities.length; i++) {
        delete entities[i].entityAspect.extraMetadata;
    }
    

    It there are no extraMetadata (which contains the odata.id) are available, breeze calculates the URI to the controller of the concrete model.

    I don't know if there's a better solution available, that the OData API sends the correct odata.id in the first place.