breezeManager.createEntity() 无法为特定值填充外键 属性

breezeManager.createEntity() fails to populate foreign key property for a specific value

我这里有两个相关的 table:

public partial class List
{...
        public int RegionId { get; set; }

        [ForeignKey("RegionId")]
        public virtual Region Region { get; set; }
...}

public partial class Region
{
    public Region()
    {
        Lists = new HashSet<List>();
    }

    public int RegionId { get; set; }

    [Required]
    [StringLength(255)]
    public string Name { get; set; }

    public DateTime Added { get; set; }

    public virtual ICollection<List> Lists { get; set; }
}

这里是地区的内容 table:

RegionId    Name
1   Global
2   China
3   USA
4   UK
8   Canada
9   Spain
10  France

在 breeze 方面,我拉下了区域:

var query = new breeze.EntityQuery().from("Regions").select("RegionId,Name").orderBy("RegionId");
    return $rootScope.breezeManager.executeQuery(query).then(function (data) {
        service.regions = data.results;

似乎有效:

service.regions[2]; // Name: "USA", RegionId: 3

但是,当我尝试创建一个新实体时:

var newList = $rootScope.breezeManager.createEntity('List', listValues);

并且在 listValues 中,我指定 { RegionId: 3, ...}:

newList.RegionId // 3
newList.Region   // null

这可能已经很奇怪了,但是 真正 令人沮丧的是,如果我指定另一个值,例如 1,它会起作用。 2 和 4 相同:

newList.RegionId     // 1
newList.Region.Name  // "Global"

我已经仔细研究了代码(和互联网)几个小时试图弄清楚这一点,但它让我望而却步,因此有资格回答我的 第一个 SO 问题!

更新

我现在更糊涂了。我计划通过在 createEntity 调用后手动设置区域来解决此问题,因此我在 createEntity:

正上方添加了这行代码
var region = Enumerable.From(service.regions).Single("$.RegionId == " + listValues.RegionId);

然而,在这样做之后,并且没有其他更改,newList 现在可以正确地获得填充的 Region,即使是 3(美国)!然后我注释掉该行并再次尝试,它仍然有效。尝试了其他几次,尝试了各种组合,现在它不再工作了,即使是那条线。不确定这是否有帮助。我会继续尝试。

我不知道你到底想做什么,但我确实看到你有一个根本性的误解。

我相信您期待您的第一个查询 return Region 个实体,并且您认为 service.regions 在成功回调中填充了 Region 个实体。

两者都不是。您的查询包含一个 select() clause,这使它成为我们所说的 projection。投影 returns 数据对象,而不是实体。缓存中也没有 Region 个实体。

You may have seen elsewhere - perhaps a Pluralsight video - where a projection query did return entities. That happens when the query includes a toType clause which actually casts the projected data into instances of the targeted type. That's a trick you should only perform with great care, knowing what you are doing, why, and the limitations. But you're not casting in this query so this digression is besides the point.

因此,service.regions 数组包含一些包含 Region 数据但不包含 Region [=59] 的数据 objects =]实体.

这也解释了为什么当您使用 RegionId:3 创建新的 List 实体时,新实体的 Region 属性 returned null.当然是null。仅根据您告诉我们的情况,缓存中根本没有 Region 个实体,更不用说 ID=3 的 Region

我无法解释您如何获得 id=1 或 id=2 的 Region。我猜你还没有告诉我们一些事情......比如你通过其他查询获得了这些区域。

我不明白你为什么首先要使用投影查询。为什么不查询所有区域并完成它?

 breeze.EntityQuery.from("Regions").orderBy("RegionId")
       .using(manager).execute(function(data) { 
           service.regions = data.results;
       });

我完全不明白你的更新;对我来说,这看起来不像是有效的 EF 查询。

切题

首先,为什么要使用 HashSet<List> 在服务器端 Region 模型 class 中初始化 Lists 属性?这是一种专门的集合类型,只会混淆这里的内容。它并不像普通人 reader 认为的那样。虽然它可以防止某人两次添加相同的对象引用,但它并没有做更重要的工作来防止某人添加两个具有相同 RegionId 的不同 List 对象。简单、明显和正确的做法是...

Lists = new System.Collections.Generic.List<List>();

// the full type name is only necessary because you burned the name "List"
// when defining your model class.

其次,在客户端,请不要用任何东西扩展 Angular $rootScope。那种全局变量"pollution"被广泛认为是"bad practice"。将您的 Breeze 内容保存在适当的 Angular 服务中,并在需要时注入该服务。