I have an OData service build with WebAPI and EF 6. I use the fluent api to create my models. It works fine, but when I use $expand
it omits entities where the expanded property is null
.
This is a simplified example:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int? AddressId { get set; } // Note that Address is optional
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street{ get; set; }
}
public class CustomersController : ODataController
{
[EnableQuery]
public virtual IQueryable<Customer> Get(ODataQueryOptions<Customer> q)
{
// I return IQueryable from DBSet here...
return db.GetDbSet<Customer>();
}
}
A Customer
doesn't need to have an address. And If I query it like /customers?$expand=Address
it will not include Customers
where Address == null
. It will only return the Customer
entities where Customer.Address
exists.
I guess it does an inner join, and therefore doesn't get the Customer
entities that doesn't have an Address
. Is there any way to include customers where address is null as well?
Current Output:
[
{
Id: 1,
Name: 'Customer1',
AddressId: 1,
Address :
{
Id: 1,
Street: 'Some street'
}
}
]
Wanted output:
[
{
Id: 1,
Name: 'Customer1',
AddressId: 1,
Address :
{
Id: 1,
Street: 'Some street'
}
},
{
Id: 2,
Name: 'Customer2',
AddressId: null,
Address : null
}
]
The models above is an example. I actually got way bigger models, but I tried to keep the example as short as possible to provide a mcve. I've read this and this question, but I'm not getting any error. I just don't get the entities at all.
It appeared that the wanted output is the normal behavior for an OData service when using $expand
. The error was caused by my mappings.
For some reason I had a bit of old code that made the Address
required, even though the foreign key itself was nullable.
public class CustomerMap : EntityTypeConfiguration<Customer>
{
public CustomerMap()
{
// Other code...
// This is wrong!
this.HasReguired(c => c.Address).WithMany(a => a.Customers);
// This is right!
this.HasOptional(c => c.Address).WithMany(a => a.Customers);
}
}
And because of the mapping, EF translated the SQL into an INNER JOIN
instead of an OUTER JOIN
.