问题包括查询中的导航属性

时间:2013-12-19 21:56:31

标签: entity-framework asp.net-web-api cors breeze

我正在使用Web API 2与来自bower的CORS / Entity Framework 6 / Breeze.js进行单页面应用程序,而breeze查询不会扩展导航属性。

我会将其从服务器分解为客户端。

// 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是HttpConfiguration

config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

//微风控制器

[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;
    }
}

//前端土地

// 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显示JSON有效负载:

[
   {
      "$id":"1",
      "$type":"DataAccess.Models.Foo, DataAccess",
      "Id":"10",
      "Bar":{
         "$id":"2",
         "$type":"DataAccess.Models.Bar, DataAccess",
         "Id":"12",
         "SomeData":"Hello World"
      }
   }
]

bar不是chrome中数组中对象的字段。


编辑:

解决方案是添加一个属性来保存BarId并将其设置为外键。

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 个答案:

答案 0 :(得分:3)

对我来说,是什么?你在依赖Foo实体中没有外键(FK)属性

您已通过映射中的t.MapKey表达式在数据库表(“Foo.BarId”)中标识了FK列。

HasRequired(t => t.Bar).WithMany().Map(t => t.MapKey("BarId"));

但您故意未在BarId实体中创建相应的Foo FK属性。

实体框架可以检索缺少FK属性的关联的对象图。因为您告诉Entity Framework有关FK 的信息,所以它可以实现服务器上的Foo及其Bar 。这就是您在线上看到相关Bar数据的原因。

但是BreezeJS无法访问数据库......也不应该有任何数据库意识。 Breeze只知道(通过元数据)您的实体类型属性。如果没有FK 属性,则Breeze无法将Bar与其父Foo相关联。

BreezeJS可能实现缓存中的Bar实体。如果你打破成功回调并在控制台中执行以下操作,我会打赌(没有承诺)你会在那里找到它:

manager.getEntities('Bar');

但是对于BreezeJS来说,这只是缓存中的另一个实体。 Breeze无法填充Foo.Bar导航属性,因为它不知道FooBar是否相关。 Breeze 需要FK属性来实现Foo.Bar导航属性

这是why we say that FK属性必须支持BreezeJS关联。

  

与缺乏FK属性的协会合作需要相当多的技能和知识 - 超出了本答案的范围。您必须使用自己的代码维护导航属性;微风无法做到。我的推荐(包括对自己):不要去那里。

如果将“Foo.cs”重新定义为

,那么一切都会好的
public class Foo
{
    public int Id { get; set; }
    public int BarId { get; set; } // Bar nav's FK
    public Bar Bar { get; set; }
}
不过,如果有人想知道,CORS不是这个问题的一个因素。