问题
I am using Web API 2 with CORS/Entity Framework 6/Breeze.js from bower for a single page application and the breeze query is not expanding the navigation property.
I'll break it down from server to client.
// POCOs
public class Foo
{
public int Id { get; set; }
public Bar Bar { get; set; }
}
public class Bar
{
public int Id { get; set; }
public string SomeData { get; set; }
}
public class FooMap : EntityTypeConfiguration<Foo>
{
public FooMap()
{
HasKey(t => t.Id);
ToTable("Foo");
Property(t => t.Id).HasColumnName("Id");
HasRequired(t => t.Bar).WithMany().Map(t => t.MapKey("BarId"));
}
}
// Web API Config // omitting static class and default route // config is HttpConfiguration
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// Breeze Controller
[BreezeController]
public class FooController : ApiController
{
readonly EFContextProvider<SomeDbContext> _contextProvider =
new EFContextProvider<SomeDbContext>();
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[HttpGet]
public IQueryable<Foo> Foos()
{
return _contextProvider.Context.Foos;
}
}
// Front end land
// main.js
breeze.NamingConvention.camelCase.setAsDefault();
var FooService = (function(breeze) {
var service = "http://localhost:58996/breeze/Foos";
breeze.config.initializeAdapaterInstances({ dataService: 'webApi' });
var manager = new breeze.EntityManager(service);
var entityQuery = new breeze.EntityQuery();
this.getAll = function(callback, errorCallback) {
return manager.executeQuery(entityQuery.from('Foo').take(10).expand('Bar'), callback, errorCallback);
};
})(window.breeze);
var fooService = new FooService();
fooService.getAll(function(data) {
console.log(data);
}, function(error) {
console.log(error);
});
Fiddler shows the JSON payload:
[
{
"$id":"1",
"$type":"DataAccess.Models.Foo, DataAccess",
"Id":"10",
"Bar":{
"$id":"2",
"$type":"DataAccess.Models.Bar, DataAccess",
"Id":"12",
"SomeData":"Hello World"
}
}
]
but bar
is not a field of the object in the array in chrome.
Edit:
The solution is to add a property to hold BarId
and set it as a foreign key.
public class Foo
{
public int Id { get; set; }
public int BarId { get; set; }
public Bar Bar { get; set; }
}
public class FooMap : EntityTypeConfiguration<Foo>
{
public FooMap()
{
HasKey(t => t.Id);
ToTable("Foo");
Property(t => t.Id).HasColumnName("Id");
Property(t => t.BarId).HasColumnName("BarId");
HasRequired(t => t.Bar).WithMany().HasForeignKey(t => t.BarId);
}
}
回答1:
What leaps out at me is that you do not have a Foreign Key (FK) property in the dependent Foo
entity.
You have identified the FK column in the database table ("Foo.BarId") through the t.MapKey
expression in your mapping.
HasRequired(t => t.Bar).WithMany().Map(t => t.MapKey("BarId"));
But you deliberately did not create a corresponding BarId
FK property in your Foo
entity.
Entity Framework can retrieve object graphs for associations that lack FK properties. Because you told Entity Framework about the FK column, it can materialize both the Foo
and its Bar
on the server. That's why you see related Bar
data on the wire.
But BreezeJS lacks access to the database ... nor should it have any database awareness at all. Breeze only knows about (through metadata) your entity type properties. Without the FK property, Breeze has no way to associate a Bar
with its parent Foo
.
BreezeJS was probably able to materialize the Bar
entity in cache. I'll bet (no promise) you'll find it there if you break in the success callback and execute the following in the console:
manager.getEntities('Bar');
But to BreezeJS, this is just another entity in cache. Breeze cannot populate the Foo.Bar
navigation property because it does not know that or how the Foo
and the Bar
are related. Breeze needs the FK property to implement that Foo.Bar
navigation property.
This is why we say that "BreezeJS associations must be supported by FK properties."
It takes considerable skill and knowledge - beyond the scope of this answer - to work with associations that lack FK properties. You would have to maintain the navigation properties with your own code; Breeze wouldn't be able to do it. My recommendation (including to myself): don't go there.
All should be well if you redefine "Foo.cs" as
public class Foo
{
public int Id { get; set; }
public int BarId { get; set; } // Bar nav's FK
public Bar Bar { get; set; }
}
Btw, in case anyone wonders, CORS is not a factor in this question.
来源:https://stackoverflow.com/questions/20692463/issues-including-navigation-properties-in-query