简体   繁体   English

返回了EntityTypes中的Breeze EntityQuery缺失数据

[英]Breeze EntityQuery missing data in EntityTypes returned

I'm setting up a SPA using Angular and Breeze. 我正在使用Angular和Breeze建立SPA。 I've been following John Papa's hot-towel tutorial from plural site. 我一直在从复数网站关注John Papa的热巾教程。 I'm having a weird issue I think might be spawning from my metadata? 我有一个奇怪的问题,我认为可能会从我的元数据产生? But in the end, I'm not really sure.... 但最后,我并不确定......

First things first, my API is running off a LAMP stack, so I'm not using EF. 首先,我的API正在运行LAMP堆栈,所以我没有使用EF。 I have created a Metadata endpoint that I think is giving me the correct structure I need. 我创建了一个元数据端点,我认为它给了我正确的结构。 I'm using the breeze.angular.q.js to help my mappings from Q to $q 我正在使用breeze.angular.q.js来帮助我从Q到$ q的映射

resource: api/v1/Metadata 资源:api / v1 /元数据

{
    "metadataVersion": "1.0.5",
    "dataServices": [
        {
            "serviceName": "api/v1/",
            "hasServerMetadata": true,
            "jsonResultsAdapter": "webApi_default",
            "useJsonp": false
        }
    ],
    "structuralTypes": [
        {
            "shortName": "tracks",
            "namespace": "MyNamespace",
            "dataProperties": [
                {
                    "name": "id",
                    "nameOnServer": "id",
                    "maxLength": 36,
                    "validators": [],
                    "dataType": "Guid",
                    "isPartOfKey": true
                },
                {
                    "name": "title",
                    "nameOnServer": "title",
                    "maxLength": 255,
                    "validators": [],
                    "dataType": "String"
                },
                {
                    "name": "description",
                    "nameOnServer": "description",
                    "maxLength": 0,
                    "validators": [],
                    "dataType": "String"
                }
            ]
        }
    ]
}

example API return data looks like this: 示例API返回数据如下所示:

resource: api/v1/tracks 资源:api / v1 / tracks

{
    "data": [
        {
            "id": "495f21d6-adfc-40b6-a41c-fc93d9275e24",
            "title": "harum",
            "description": "Error doloribus ipsam et sunt fugiat."
        },
        {
            "id": "d7b141d2-6523-4777-8b5a-3d47cc23a0fe",
            "title": "necessitatibus",
            "description": "Voluptatem odit nulla maiores minima eius et."
        }
    ],
    "embeds": [
        "courses"
    ]
}

Now w/ all my code, I'm actually returning correct data from my api. 现在w /我的所有代码,我实际上是从我的api返回正确的数据。 I've poured over examples from the breeze site as a few good tidbits I found here on SO ( like this question and great answer from ward ). 我已经把微风网站上的例子作为我在SO上找到的一些好花絮( 这个问题和来自病房的好答案 )。 Alas, no luck. 唉,没有运气。 Essentially whats happening is when I try to loop over my results, in my view model, that are returned from my breeze query, I get an angular error Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: t in vm.tracks, Duplicate key: object:00I 基本上发生的事情是当我尝试在我的视图模型中循环我的结果时,从我的微风查询返回,我得到一个角度错误Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: t in vm.tracks, Duplicate key: object:00I Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: t in vm.tracks, Duplicate key: object:00I

The call is happening in a function inside my datacontext. 调用发生在我的datacontext中的一个函数中。 The data returned in my querySucceeded promise callback doesn't appear to be correctly bound. 我的querySucceeded promise回调中返回的数据似乎没有被正确绑定。

datacontext.js datacontext.js

...
function getTrackPartials() {
    ...
    return EntityQuery.from(entityNames.track)
        .toType(entityNames.track)
        .using(manager).execute()
        .then(querySucceeded, _queryFailed);

    function querySucceeded(data) {
        console.log(data);  // <--  Log out to see what is returned
        tracks = data.results;
        _areTracksLoaded(true)
        log('Retrieved [Track Partials] from remote data source', tracks.length, true);
        return tracks;
    }
}

If I were to log this data out to the console, I get this (all the $$hashKey's are the same, and the id, title, description are all NULL. But I do get the correct number of results, and this isn't a coincidence - if I adjust the number of results I'm supposed to receive, it correctly matches every time). 如果我将这些数据记录到控制台,我得到这个(所有的$$ hashKey是相同的,id,title,description都是NULL。但是我得到了正确的结果数,这不是'巧合 - 如果我调整我应该接收的结果数量,它每次都正确匹配)。

querySucceeded promise回调

Now, since my data comes back a little bit different - I used the Edmonds example and created a custom JsonResultsAdapter so I could "massage" the data. 现在,由于我的数据有点不同 - 我使用了Edmonds示例并创建了一个自定义的JsonResultsAdapter因此我可以“按摩”数据。 Its very rudimentary at the moment, as I'm just trying to get this working. 目前它非常简陋,因为我只是想让它起作用。 Whats really throwing me off, is if I log out the node parameter from the visitNode function in the JsonResultsAdapter , it has the correct data....???? 什么真的让我失望,如果我从visitNode中的JsonResultsAdapter函数注销node参数,它有正确的数据.... ???

entityManagerFactory.js entityManagerFactory.js

(function () {
    'use strict';

    var serviceId = 'entityManagerFactory';
    angular.module('app').factory(serviceId, ['config', emFactory]);

    function emFactory(config) {
        breeze.config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
        breeze.NamingConvention.camelCase.setAsDefault();

        var serviceName = config.remoteServiceName;
        var metadataStore = new breeze.MetadataStore();

        var provider = {
            metadataStore: metadataStore,
            newManager: newManager
        };

        var jsonResultsAdapter = new breeze.JsonResultsAdapter({
            name: "Tracks",
            extractResults: function(json) {
                console.log(json.results.data);  // <--  Log out to see what is returned
                return json.results.data;
            },
            visitNode: function(node, mappingContext, nodeContext) {
                console.log(node);  // <--  Log out to see what is returned
                return {
                    entityType: 'tracks',
                    nodeId: node.id
                };
            }
        });

        var dataService = new breeze.DataService({
            serviceName: serviceName,
            jsonResultsAdapter: jsonResultsAdapter
        });

        return provider;

        function newManager() {
            var mgr = new breeze.EntityManager({
                dataService: dataService,
                metadataStore: metadataStore
            });

            return mgr
        }
    }
})();

Here is my return value from my JsonResultsAdapter::extractResults function 这是我的JsonResultsAdapter :: extractResults函数的返回值 JsonResultsAdapter extractResults返回值

Here is a node from my JsonResultsAdapter::visitNode function 这是我的JsonResultsAdapter :: visitNode函数中的一个节点 JsonResultsAdapter visitNode节点参数

Any help would be appreciated. 任何帮助,将不胜感激。 Like I said, I'm not really sure where the error is happening at? 就像我说的,我不确定错误发生在哪里? But if i had to guess, I would say there is some disconnect between my EntityQuery using my manager and the JsonResultsAdapter, that might be caused by bad metadata I've generated. 但是,如果我不得不猜测,我会说我的EntityQuery使用我的经理和JsonResultsAdapter之间存在一些脱节,这可能是由我生成的错误元数据引起的。

** UPDATE ** ** 更新 **

So I walked through the breeze code to figure out where I'm loosing my data and was able to figure out whats going on and a way to fix it. 所以我浏览了微风代码,找出了我丢失数据的地方,并且能够弄清楚最新情况和解决方法。 However, I'm not sure if thats the best way to actually handle this. 但是,我不确定这是否是实际处理此问题的最佳方法。

I should mention, I used bower to install breeze - and by doing such I went the bower-breeze-angular git://github.com/eggers/bower-breeze-angular.git package and not the default breeze breeze git://github.com/IdeaBlade/Breeze.git which is bloated with examples and other data I wasn't keen on packing into my repo. 我应该提一下,我用凉亭来安装微风 - 通过这样做我去了bower-breeze-angular git://github.com/eggers/bower-breeze-angular.git包而不是默认的微风breeze git://github.com/IdeaBlade/Breeze.git随着示例和其他数据而膨胀,我并不热衷于打包到我的回购中。

In breeze, after my JsonResultsAdapter::visitnode callback has returned, it needs to " merge " my data, the problem I have is the entityKey that is returned from my node is not matching up. 在微风中,在我的JsonResultsAdapter::visitnode回调返回之后,它需要“ 合并 ”我的数据,我遇到的问题是从我的节点返回的entityKey不匹配。 This is because the rawValueFn from my mappingContext is looking for nameOnServer , which I thought I set in my metadata from my server - but somehow when I log out my dataproperty it has changed from what I set. 这是因为rawValueFn从我mappingContext正在寻找nameOnServer ,我认为我在从我的服务器我的元数据集-但不知何故,当我登录了我的dataproperty它已经从我的设置改变。

This is one dp logged out, if you look back up at the top in my Metadata resource call, I specifically set this to "id". 这是一个dp注销,如果你回顾我的元数据资源调用中的顶部,我特意将其设置为“id”。 How did this change to Id? 这是如何改变为Id的? Thats whats causing my headache! 那是什么导致我的头痛!

DataProperty已更改nameOnServer密钥

I can get around this by updating my rawValueFn function on my mappingContext in my JsonResultsAdapter and everything will work - but this feels like a "hack". 我可以通过在我的JsonResultsAdapter中的mappingContext上更新我的rawValueFn函数来解决这个JsonResultsAdapter ,一切都会起作用 - 但这感觉就像是“黑客”。 I've also tried playing w/ the "NamingConvention" but that doesn't seem to work either. 我也试过玩“NamingConvention”,但这似乎也不起作用。

Here is my updated JsonFactory that makes it work 这是我更新的JsonFactory,它使它工作

    var jsonResultsAdapter = new breeze.JsonResultsAdapter({
        name: "Tracks",
        extractResults: function(json) {
            return json.results.data;
        },
        visitNode: function(node, mappingContext, nodeContext) {

            // Had to adjust this so it would lowercase and correctly match
            mappingContext.rawValueFn = function(rawEntity, dp) {
                name = dp.name;
                name.substring(0, 1).toLowerCase() + name.substring(1);
                return rawEntity[name];
            }

            return {
                entityType: 'tracks'
            };
        }   
    }); 

Wow this is a long question. 哇这是一个很长的问题。

First , I recommend that you look at the "Metadata by hand" topic which describes a much simpler way to define your metadata ... using the Breeze Labs metadata helper. 首先 ,我建议您查看“手工元数据”主题,该主题描述了使用Breeze Labs元数据帮助程序定义元数据的更简单方法。 That will cut down a lot of the tedium and make it much clearer to read and understand. 这将减少很多单调乏味,使阅读和理解更加清晰。

Second , do NOT specify "jsonResultsAdapter" in your metadata. 其次请勿在元数据中指定“jsonResultsAdapter”。 It looks to me like your pinning your metadata to the WebAPI adapter when, in fact, you want to use a different one. 在我看来,就像你将元数据固定到WebAPI适配器一样,事实上,你想要使用另一个。 Do NOT specify the "namingConvention" in your metadata either as that will trump whatever you set elsewhere. 不要在元数据中指定“namingConvention”,因为这将胜过您在其他地方设置的内容。 And given that you are not getting metadata from the server, "hasServerMetadata" should be false if you bother to set it at all (which you shouldn't). 并且鉴于您没有从服务器获取元数据,“hasServerMetadata”应该是false如果你懒得设置它(你不应该)。

Third , stick to the client-side name and forget about "nameOnServer". 第三 ,坚持客户端名称,忘记“nameOnServer”。 The NamingConvention is going to crush that anyway. 无论如何, NamingConvention将会粉碎。

Fourth , if (as it appears) the client-side and server-side property names are BOTH camelCase DO NOT change the NamingConvention default! 第四 ,如果(看起来)客户端和服务器端属性名称是两个camelCase 不要更改NamingConvention默认值! You don't want any translation. 你不想要任何翻译。 The default does no translation. 默认不进行翻译。

If I'm correct about that, do NOT change the NamingConvention to camelCase! 如果我对此是正确的,请不要NamingConvention更改为camelCase! The "camelCase" convention tells Breeze " the server is PascalCase so translate my client-side camel case property names into Pascal names on the server ". “camelCase”约定告诉Breeze“ 服务器是PascalCase,所以将我的客户端camel case属性名称转换为服务器上的Pascal名称 ”。 If I understand correctly, you don't want client-side "id" to become server-side "Id" ... which is what will happen. 如果我理解正确,您不希望客户端“id”成为服务器端“Id”......这将会发生什么。 That's why (I believe) you are seeing "Id" as the "nameOnServer". 这就是为什么(我相信)你看到“Id”作为“nameOnServer”。

Fifth , within a JsonResultsAdapter , the node names match the JSON from your server and, therefore, are server-side names. 第五 ,在JsonResultsAdapter ,节点名称与服务器中的JSON匹配,因此是服务器端名称。 Keep them that way. 保持这种方式。 The NamingConvention will convert them to client-side names when it translates node property values to entity property values. 当NamingConvention将节点属性值转换为实体属性值时,它们会将它们转换为客户端名称。 In fact, you'll lose data if you mistakenly use client-side names on the nodes. 实际上,如果您错误地在节点上使用客户端名称,您将丢失数据。

Do you have some need to mutate property names and values in the JSON as it arrives from the server? 当你从服务器到达时,你是否需要改变JSON中的属性名称和值? If not, don't mess with those names in your visitNode method. 如果没有,请不要在visitNode方法中弄乱这些名称。 About all you'll need to do is make sure that you identify the correct EntityType for the node and return that in the result. 关于您需要做的就是确保为节点识别正确的EntityType并在结果中返回该EntityType

Sixth , I'm pretty sure the "entityType" property of the visitNode result must be an actual EntityType , NOT the name of the type as you have shown in your example. 第六 ,我很确定visitNode结果的“entityType”属性必须是实际的EntityType ,而不是您在示例中显示的类型的名称 You can't say 你不能说

return {
   entityType: 'tracks',
};

You have to give it the real type (I'm pretty sure) 你必须给它真正的类型(我很确定)

return {
   entityType: trackType,
};

Look at the other Breeze adapters (eg, the Web API adapter). 查看其他Breeze适配器(例如,Web API适配器)。 It gets the EntityType from the MetadataStore . 它从MetadataStore获取EntityType

Seventh Why are you setting the "nodeId"? 第七个为什么要设置“nodeId”? I'm not saying you're wrong to do so. 我不是说你做错了。 But you should know why. 但你应该知道为什么。 The "nodeId" is used to help reconstruct an object graph when the same entity appears multiple times in the payload. “nodeId”用于在同一实体在有效载荷中多次出现时帮助重建对象图。 It is only useful when accompanied by a "nodeRefId" in some other node which points to a "nodeId" value. 只有当某个其他节点中的“nodeRefId”指向“nodeId”值时,它才有用。 At this point, where you only have one kind of entity and not relationships, setting the "nodeId" isn't accomplishing anything. 此时,只有一种实体而不是关系,设置“nodeId”并不能完成任何事情。 Later it will ... but only if you're setting it with a value that makes sense. 稍后它会......但只有你用一个有意义的值设置它。

What I think you're doing is setting the "nodeId" to the primary key value of Track . 我认为您正在做的是将“nodeId”设置Track主键值 Isn't that what node.id is in your case? 这不是你的情况下node.id吗? If I'm right, don't do that . 如果我是对的, 不要这样做 The "nodeId" is NOT the PK of your entity. “nodeId” 不是您实体的PK。 It is a marker for serializing entity graphs with cycles. 它是用循环序列化实体图的标记。

Wow mine is a long answer 哇,我的答案很长

I fear you are a bit over your head here. 我担心你在这里有点过头了。 Writing a dataService adapter or a jsonResultsAdapter is not a Breeze beginner task. 编写dataService适配器或jsonResultsAdapter不是Breeze初学者任务。 If you're going to go there, please study the existing adapters and follow them meticulously. 如果你要去那里,请研究现有的适配器并仔细地遵循它们。 Know why they do what they do rather than wing it. 知道为什么他们做他们做的事而不是甩它。

I hope I've provided a few clues here. 我希望我在这里提供了一些线索。

I suspect it is much simpler than you're making it. 我怀疑它比你制作它简单得多。 Some key thoughts: 一些关键的想法:

  • Make sure you aren't changing the NamingConvention unless you really do need to change the spelling of property names from client-to-server. 除非确实需要从客户端到服务器更改属性名称的拼写,否则请确保不要更改NamingConvention

  • Set the "entityType" in your JsonResultsAdapter to an EntityType , not the name of the type. 将JsonResultsAdapter中的“entityType”设置为EntityType ,而不是类型的名称。

  • Don't rewrite breeze functions like rawValueFn ; 不要重写像rawValueFn这样的breeze函数; you'll break Breeze and you won't know how or why. 你将打破微风,你不会知道如何或为什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM