Search code examples
c#entity-frameworkasp.net-web-apiodata

OData $expand does not include entities where expanded property is null


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.


Solution

  • 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.