Search code examples
ef-code-firstentity-framework-5breezetable-per-type

BreezeJs Fails to Load Metadata for EF Code First Schema with Inherited Class


Just started trying out Breeze today, long time EF user - think I found a bug in Breeze, but I may be doing something wrong - want to know which it is:

I have a simple hierarchy in EF Code First:

// For testimonials about the product line in general
public class Testimonial
{
    public int Id { get; set; }

    public string Text { get; set; }
}

// For testimonials specific to a single product
[Table("ProductTestimonial")]
public class ProductTestimonial : Testimonial
{
    public Product Product { get; set; }
}

So just to be clear there's 2 tables here, Testimonial and ProductTestimonial, both have a PK of Id, and a Text field, and one of them also has an FK off to Product. This is just a simple way of implementing Table Per Type.

So I setup the BreezeController via WebApi:

[BreezeController]
public class EFController : ApiController
{
    private readonly EFContextProvider<EfDb> _db = new EFContextProvider<EfDb>();

    [HttpGet]
    public string Metadata()
    {
        return _db.Metadata();
    }

And I go to load it in breeze.js:

var manager = new breeze.EntityManager('/api/ef');
manager.executeQuery(breeze.EntityQuery.from('Product');

Kablamo. Exception. It says:

Unable to get value of the property 'propertyRef': object is null or undefined

At:

function convertFromODataEntityType(... {
    . . .
    var keyNamesOnServer = toArray(odataEntityType.key.propertyRef)...

Where odataEntityType.name == 'ProductTestimonial', and .key sure enough is undefined.

Which is true. Picking things apart, when I call executeQuery(), Breeze hits the Metadata call on the WebApi, which I verified calls and returns successfully. The massive JSON string returned from there includes:

{
    "name": "ProductTestimonial",
    "baseType": "Self.Testimonial",
    "navigationProperty": {
        "name": "Product",
        "relationship": "Self.ProductTestimonial_Product",
        "fromRole": "ProductTestimonial_Product_Source",
        "toRole": "ProductTestimonial_Product_Target"
    }
},
{
    "name": "Testimonial",
    "key": {
        "propertyRef": {
            "name": "Id"
        }
    },

So it would appear the basic issue is that the Metadata is accurately portraying ProductTestimonial as an inherited class, whose key is defined elsewhere, but Breeze.js - if I'm understanding it correctly - is naively just checking the .key property without considering superclasses. But, I could be wrong since I'm so new to Breeze.

Addendum:

I don't think it's relevant here but in case it comes up, yes I do have an IQueryable as well on the WebApi Controller:

[HttpGet]
public IQueryable<Product> Products()
{
    return _db.Context.Products;
}

Also, I recognize a potential workaround here is probably to discard TPT and make full classes for every Entity with no inheritance, but I'm really slimming my example down here - there's a lot of inheritance throughout the EF model that has to stay. If it's inheritance or Breeze, Breeze is getting the axe.


Solution

  • Edit: As of v 1.3.1 Breeze now DOES support inheritance.

    Inheritance is coming but we don't have a fixed date just yet. Please vote for the feature on the Breeze User Voice. We take these suggestions very seriously.