Breeze / breeze.server.net

Breeze support for .NET servers
MIT License
76 stars 62 forks source link

Selecting nullable navigation propery results in server error #69

Closed wijnsema closed 2 years ago

wijnsema commented 6 years ago

Hello,

Suppose I have the following (simplified) Entity model:

public class Invoice 
{
   public int Id { get; set }
   public int CustomerId { get; set; }   <= not nullable
   public int? CategorieId { get; set; }  <= nullable!
   public virtual Customer Customer
   public virtual Category Category
   //much more properties...
}
public class Customer
{
   public int Id { get; set; }
   public string Name { get; set }
}
public class InvoiceType
{
   public int Id { get; set; }
   public string Title{ get; set }
}

When I query this with Breeze server and Breeze Javascript client like this:

let q = new breeze.EntityQuery()
   .from('Invoices')
   .select('Customer.Name')

it works perfectly alright.

However, when I select a nullable column/property, e.g.

let q = new breeze.EntityQuery()
   .from('Invoices')
   .select('Category.Title')

and hit a row without an InvoiceType a server error occurs:

System.InvalidOperationException: The cast to value type 'InvoiceType' failed 
because the materialized value is null. Either the result type's generic parameter or 
the query must use a nullable type.

I can reproduce this behaviour in a Linqpad query: Invoices.Select(x => new { x.Id, x.InvoiceType .Title }) will result in an error for rows without InvoiceType.

However, in Linqpad I can easily fix this: Invoices.Select(x => new { x.Id, Title = x.InvoiceType == null ? null : x.InvoiceType.Title })

I can't do this on the client...

Is this some kind of edge case, or a bug maybe?

I'm using the Core version of Breeze server.

marcelgood commented 6 years ago

No, this isn't a bug. It's simply a case of a select that you can't express on the client. The Breeze query language on the client is fairly limited on what you can do. This is a case where you should create a dedicated server endpoint that handles this projection safely, instead of doing the select on the client. Or change the server endpoint's base query to ensure that InvoiceType is never null.

marcelgood commented 6 years ago

After discussing this on our end, I've been told that this scenario should be handled by Breeze and it might indeed by a bug. We'll have to look into it. In the meantime, the workaround I described above should still work. Just to make sure, are you using EF 6 or EF Core?

wijnsema commented 6 years ago

Hi @marcelgood,

First of all sorry for my long absence. Some rare bacteria struck me and kept me hospitalized for 16 days...

Good to see that you are taking this case seriously, I do feel that this case should be supported just as null values in a flat query are.

If I can be of any assistance (e.g. testing) please let me know.

The context where I use this query is to create a fully functional CRUD UI based on just the Metadata supplied by breeze. The database can have any structure. That's why I can't use the workarounds you mentioned.

A workaround which is feasible (but complex) is to split the query in two parts:

and then combine the results into one result set on the client. But for tables with two nullable FK columns this would need four queries, for three columns 8 queries, clearly not ideal.

To answer your last question, I'm using EF 6, not EF 6 Core because it is still missing vital parts.

Thank you very much for your interest in this case, and for your work on Breeze of course!