11

I have a WebAPI backend that provides inventory information, etc. to various clients, using ODATA v3 (I cannot use v4 due to a restriction in a component that we use). The inventory database is quite large (100K+ records) and ODATA is great for server-side filtering, pagination, etc. and keeping the data transfers lean.

The inventory records have some properties that are not mapped, but rather calculated and populated on the fly as the queries are made. For example:

[NotMapped]
public decimal RebateAmount { get; set; }

The problem is that ODATA ignores any NotMapped properties, so they never get sent back to the clients.

I know this has been asked before, but that was a while ago now so I was hoping that support for this has been added by now or that somebody has a simple workaround (short of letting EF create these fields in the DB).

I have tried this ugly workaround, but it did not work (RebateAmount still does not get included by ODATA):

private decimal _rebateAmount;
public decimal RebateAmount { get {return _rebateAmount; } }

public void SetRebateAmount(decimal amount)
{
   _rebateAmount = amount;
}

Is there a (preferably simple) way to include non-DB properties in ODATA result sets?

Edit 1/7/2017 For this to be useful in my scenario, ODATA needs to also include the calculated fields in its metadata, otherwise the auto-generated (client-side) proxy classes will not include them.

Lars335
  • 1,730
  • 2
  • 22
  • 35

4 Answers4

10

I know this is an old post but in the WebApiConfig file just add the following and it will expose the "NotMapped" property.

builder.StructuralTypes.First(t => t.ClrType == typeof(YourModel)).AddProperty(typeof(YourModel).GetProperty("RebateAmount"));

Where "builder" is your IEdmModel. Most likely in your "GetEdmModel" method.

goroth
  • 2,510
  • 5
  • 35
  • 66
  • This solution does not work in Odata version 7.5x. It's not generating the metadata. Any Idea? – Rahul May 14 '19 at 11:26
  • @Rahul I just checked 7.5.4 and it is still working. What error are you receiving when you go to odata/$metadata? If you comment out the specific line for "AddProperty" does the metadata still generate? – goroth May 14 '19 at 13:14
  • @goroth I'm not receiving any error messages, but when I browse the odata/$metadata it shows a blank web page. if I comment the code then I can access the metadata page. – Rahul May 14 '19 at 15:40
  • @Rahul Are you hosting in IIS or IIS Express? Sounds like you have a higher level exception you are not catching or hiding. Might want to add an IExceptionHandler in your global.asax Application_Start(), also might want to put a break point on the AddProperty in your WebApiConfig and then run the app, it will not hit the break point but once it is running just edit your web.config by adding a space and hitting save, this will force IIS to recycle and you will then hit your breakpoint to debug WebApiConfig. – goroth May 14 '19 at 17:27
6

The easiest way (at least for EF Core): Use fluent-api!

Instead of NotMapped-Attribute you can define it like this:

modelBuilder.Entity<Product>().Ignore(p => p.RebateAmount);

For EF6 you should also look at this question: EF Code First prevent property mapping with Fluent API

Joshit
  • 1,238
  • 16
  • 38
2

One approach could be by creating OData EDMModel with a DTO object with the additional computed property.

Please check this answer which has the implemetation details to do this: Mapping OData query against a DTO to another entity?

The DTO can be mapped by a View at Database server or can be calculated in controller by using OdataQueryOptions.

Community
  • 1
  • 1
Ankit
  • 2,448
  • 3
  • 20
  • 33
  • I started implementing your suggestion, but it turned out to add quite a bit of complexity (more than I am comfortable with for this); if there is no less intrusive way of accomplish this, I will just bite the bullet and put the properties in the DB. But thanks for your suggestion! – Lars335 Jan 08 '17 at 01:58
  • I forgot to mention that I use ODATA 3 (I have updated the question), so this explains at least one issue I had when trying to implement your suggestion. Either way, I have upvoted you for taking the time to suggest a possible solution. – Lars335 Jan 09 '17 at 03:48
  • I had to implement such a case previously, and unfortunately I could not find any simpler solution to this and had created a custom IQueryable using OdataQueryOptions to work with the custom EdmModel. I would follow this question for updates on better solutions. – Ankit Jan 09 '17 at 11:19
  • I am curious: were you using ODATA 3 or ODATA 4? – Lars335 Jan 09 '17 at 16:23
0

If you run into this issue, the above suggestions don't work in later versions of EF. I was able to get it working with the following:

// Add this to the DB Context:
// *****************************************
modelBuilder.Entity<ModelObject>().Ignore(a => a.PropertyName);

// Add this to the Model Object
// *****************************************
public string PropertyName { 
    get { return _expression1.Evaluate(this); } 
    set { }     // # This is the magic piece that makes it work
}

The magic piece being the setter.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Chris
  • 1