My unmapped properties in breeze does not seems to work whith a projection
Asked Answered
G

2

0

I have the following Entity:

public class Invoice
{
    [Key]
    public int Id { get; set; }
    public DateTime? ArchiveDate { get; set; }
    public DateTime? ClotureDate { get; set; }
    ...
}

I would like to know whether my invoice is archived or closed by using a kind of flag (boolean). For that purpose I added 2 unmapped properties in my breeze entity like this:

public class Invoice
{
    [Key]
    public int Id { get; set; }
    public DateTime? ArchiveDate { get; set; }
    public DateTime? ClotureDate { get; set; }
    [NotMapped]
    public bool Archived { get { return ArchiveDate.HasValue; } } 
    [NotMapped]
    public bool Clotured { get { return ClotureDate.HasValue; } } 
    ...
}

Now I can query my breeze entity like this:

var query = entityQuery.from("Invoices")
                       .where('id', '==', id)
                       .toType('Invoice');

The call above will return all properties of my invoice entity (including archived & clotured). It works well.

But I need only a few specific properties (for performance). Then I try:

var query = entityQuery.from("Invoices")
                       .where('id', '==', id)
                       .select("id, archived, clotured")
                       .toType('Invoice');

I got the error: The specified type member 'Archived' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Very frustrating. Any idea why do I cannot perform such query?

Or maybe does someone have another solution?

Many thanks.

Groscr answered 31/10, 2013 at 16:21 Comment(2)
It is fairly clear from the error - you have created an additional property on the object that is not a property of the entity, therefore you cannot use a linq to entities query against that property. Consider persisting the property into your DBMauro
I was hoping for a solution where I don't have to persist this info in my DB because this is redundant with corresponding dates.Groscr
S
2

Short version

What you are seeing is perfectly expected. The ArchivedDate is both a persisted data property and a serialized property. The Archived property is not persisted but it is serialized. That's why you see data values for both ArchivedDate and Archived. However, your remote query ... the LINQ query executed on the server ... may only refer to the persisted properties such as ArchivedDate. EF knows nothing about calculated properties such as Archived; they cannot participate in a LINQ query ... not in a where, select, orderBy or any other query. You can't mention something in a query that EF doesn't know about ... and you told EF (properly) to ignore these Archived and Clotured calculated properties.

Long version

The [Unmapped] attribute hides the properties from EF ... as it must because Archived and Clotured are calculated properties, not persistable data.

The [Unmapped] attribute also hides these properties from the metadata generated from EF. That too is both expected and good.

But this also means that you cannot construct a LINQ query that references these properties. They aren't data properties. They can't be queried by EF. Only data properties and navigation properties can appear in a LINQ query. It is really that simple.

Perhaps you're wondering why the unmapped calculated property values are actually communicated to the JavaScript client, why those values appear in the JSON payload and would populate the like-named Breeze entity properties if you add such properties to the client metadata for Invoice as "unmapped properties".

To understand why, you must understand the difference between properties that you query with EF and the properties that you serialize with Json.NET. After the EF query completes, the materialized entities have both the data properties (e.g., ArchivedDate) and the calculated properties (Archived). The [NotMapped] attribute doesn't hide a property from Json.NET. Json.NET serializes ALL properties of the materialized object - both data and calculated properties - unless you tell it not to. For example you could hide the Archived property from Json.NET serialization with the [Ignore] attribute.

The toType is a red herring and has no bearing on the matter.

Staub answered 1/11, 2013 at 6:35 Comment(0)
L
0

Remove the ".toType('Invoice')' line from your query. Just go with:

 var query = entityQuery.from("Invoices")
                   .where('id', '==', id)
                   .select("id, archived, clotured");

This forces breeze to coerce your projection into an Invoice entity type. If you leave it off you will get a true projection, i.e. a plain javascript object with just the properties you have specified, i.e. not an entity.

Luculent answered 31/10, 2013 at 16:50 Comment(2)
I tried as you suggested: removing .toType('Invoice') but I still got the error mentionned in my question !?Groscr
Ok, in that case you need to either remove the [NotMapped] attribute or convert "Archived" back into a property that Entity Framework can query. This is really purely an EF issue.Luculent

© 2022 - 2024 — McMap. All rights reserved.