1

この質問は長くなるかもしれないので、私に固執してください!現在、私が働いている Web ベースのアプリの設計とプロトタイピングを行っています。これは、多くの複雑さと複雑さ、そして大量のデータを備えた大きなアプリです。

フロントエンド技術に関しては、Durandal、Knockout、TypeScript (すべての JavaScript および jQuery コードを記述するため) を使用して SPA を構築します。

バックエンドは非常に慎重に検討され、設計されています。簡単に言うと、慎重に設計されたドメイン モデルを使用する一連のアプリケーション サービス (nHibernate、AutoFac などを使用) があります。次に、WebAPI はアプリケーション サービスのメソッドを使用して、データをフロント エンドに返します。

DB とのやり取りが多い SPA を構築する際の明らかな考えは、Breeze を検討することです。Breeze が優れている理由は、十分に文書化されています。問題は、それが私たちのアーキテクチャに適合するかどうか確信が持てないことです。単純なプロトタイプを超えて Breeze を使用した人は誰もいないので、次の質問に答えてくれる人がいれば、とても感謝しています!

1 - デフォルトで Breeze を使用するとビジネス ロジックをバイパスし、nHibernate または DB に直接移動すると想定するのは正しいですか? この仮定が正しい場合、それを回避する方法はありますか? アドバイス/リンクはありますか?Breeze がビジネス ロジックにルーティングしてメタデータを Breeze に戻すには、アダプタを作成する必要があると考えました。これにより、システムのさまざまな部分に部分的および完全にハイドレートされたモデルがあり、外部キーが射影されるなど、他の問題が発生します。これは私たちにとって非常に論争の的となる問題です!

2 - TypeScript を使用する多くの理由の 1 つは、静的な型付きオブジェクトを Intellisense で提供することです。Breeze を使用した場合、すぐに使用できるとは限りません。

3 - キャッシュはまったく必要ありません。Breeze のこの部分を完全にオフにすることはできますか?

4 - クエリ機能を使用していない場合 (絶対に使用していません。検索の計画があります。つまり、Breeze クエリ機能と一緒に使用することはオプションではありません)、キャッシュ機能を使用しておらず、使用できます。 Breeze が許可する開発のスピードとコードの削減を支援するために、適切な場所 (DTO から TypeScript オブジェクトを自動的に生成する T4 テンプレートなど) を配置すると、Breeze を使用する意味が否定されますか?

私は多くの検索を行いましたが、Breeze を使用する必要がある理由を見つけることができます。それが素晴らしいことは認めますが、これまでの私の理解では、それが私たちのアプリに合っているかどうかはわかりません. アドバイスや推奨される読書は大歓迎です。Breeze はまだ登場したばかりなので、多くの情報を見つけるのに苦労しています。

4

3 に答える 3

2

1) サーバー上の Breeze 内で任意のクエリをインターセプトまたは保存できます。保存の場合、これは ContextProvider の BeforeSaveEntities および BeforeSaveEntity オーバーライド可能なメソッドで行われます。クエリの場合、これはサーバー側のエンドポイント メソッドのカスタム コードを介して簡単に実行できます。これらの手法はどちらも Breeze のドキュメントで説明されており、Breeze zip 内の DocCode サンプルに例があります。

2) Typescript で Breeze を使用し、Breeze メタデータを使用して Typescript クラス定義を生成している顧客がいます。後日、この種のコードのバージョンを一般消費者向けに提供する予定です。(現在、Typescript関連業務のコンサルティングサポートを行っております。お問い合わせ先はbreeze@ideablade.comです。)

3) 1 か月以内に、Breeze の次のバージョンにnoTrackingオプションを提供する予定です。現在、これと同じ効果は、「射影」クエリを実行するだけで再現できます。

4) Breeze で独自のクエリ システムを使用しても問題ありません。Breeze ドキュメントの「namedQuery」の説明を参照してください。必要に応じて、クライアント側のフィルタリングを追加して基本的なクエリを拡張することもできます。

あなたのより大きなポイントに。キャッシングや Breeze クエリの拡張機能を使用する予定がない場合、Breeze はおそらく適切ではありません

ただし、キャッシュの値は、実際に評価する必要があるものです。計画している場合は、この機能を自分で再作成する必要がある可能性があります

  1. 切断された方法でアプリを実行します。これには、ローカル ストレージからのシリアル化と逆シリアル化が含まれます。

  2. 取得済みのデータについては、クライアントとサーバー間の往復を減らします。これは、アプリが大きくなるにつれて、パフォーマンスが大幅に向上する可能性があります。

  3. 現在のマシンのメモリ内にあるものだけに対してクエリを実行する機能。

  4. 個別に取得したときに相互に関連するエンティティのグラフを自動的に接続します。

  5. 変更の追跡と、エンティティを最初にクエリされた状態に戻す機能。

他にもいくつかの問題があり、列挙するのが面倒です。

お役に立てれば!

于 2013-10-31T18:48:24.187 に答える
1

私はジェイの答えを承認し、積み上げます。Jay はそれについて言及しませんでしたが、NHibernate は現在サポートされています。

IQueryable サポートをスキップする人がいても問題ありません。ブリーズはそれについてクールです。微風 EntityQuery を引き続き使用して、任意の GET エンドポイントにヒットし、必要に応じてパラメーターを渡すことができます。それは、「上級者向け」に進み、ajax アダプターの微調整を開始する前です。

または、好きな AJAX 装置を使用してデータを取得/保存し、プロセスに簡単に組み込むことができます。間もなくリリースされるリリースでは、JSON データをどのように取得したかに関係なく、エンティティとしてキャッシュにマージすることがさらに簡単になります。

多くの人は、API を支配する傾向がある参照リストなどの簡単なものにバニラ ブリーズを使用するハイブリッド アプローチを選択します。ただし、特別な処理が必要な API の重要な「20%」については、カスタム アプローチに切り替える予定です。

キャッシュをまったく使用したくない理由を知りたいです。一部のクエリでそれを望まない理由がわかります。しかし、決して

クライアント側のデータを受信した瞬間にサーバーと同期していないことに気付きます。本当に時間の問題です。キャッシングにより、データが次第に古くなる可能性がある時間が長くなります。しかし、サーバーを離れた瞬間にすでに腐っています。

キャッシュは永遠ではありません。キャッシュ内の個々のエンティティはいつでも更新できます。キャッシュはいつでもクリアできます。そして、データの揮発性に応じて、またはおそらくサーバーからの通知に応じて、好きなだけ両方を実行します (SignalR で行う可能性のあるサイドバンド処理)。

Breeze の多くの利点を体験するには、キャッシュ内の本格的なエンティティが不可欠です。

  • 複数のビュー間で共通データを簡単に共有
  • ビュー全体でエンティティ データの現在の状態 (検証エラー メッセージを含む) を公開します。
  • ダーティな状態を追跡する ( EntityState.Modified )
  • プロパティが変更されたときの自動検証
  • 関連するエンティティに移動します: order.lineitem[0].product.name
  • セルフアセンブル エンティティ グラフのおかげで、クエリ ペイロードを縮小します (つまり、Breeze がクエリされた製品のデータを受け取ると、 shippermanufacturerproductType、およびproductPricingなどの製品の関連参照エンティティへのナビゲーション プロパティを自動的に構築します ... これらを想定)すべてキャッシュにあります。
  • 保留中の変更を元に戻す
  • キャッシュを照会する
  • 変更をローカルに隠し、保持された変更状態とともに復元します。

それぞれ独自の有効期間を持つ個別のキャッシュを必要な数だけ持つことができます。

覚えておいてください...キャッシュを制御します。

それで、あなたはキャッシュに対して何を得ましたか?

于 2013-10-31T22:42:25.233 に答える
1

新しいキャッシュを維持する

10 月 31 日のコメントは、リソースを新鮮に保ち、キャッシュを使用できることを思い出させてくれます。「どちらか/または」ではありません!

次の手順を実行してください。

  1. そのリソースを使用する前に、必ず再クエリを実行してください (たとえば、ViewModel がビューをロードするとき)。
  2. そのクエリを発行する前に、そのリソース タイプのすべてのインスタンスのキャッシュをクリアします。

両方の考えをdatacontext.getXXXメソッドにカプセル化できます。これが私が意味することです:

// 請求書のキャッシュをクリアした後、オプションでフィルタリングされた新しい請求書を取得します
function getInvoices(optionalPredicate) {
    clearCachedInvoices();
    var query = Breeze.EntityQuery.from('Invoices');
    if (optionalPredicate) { query = query.where(predicate); }
    manager.executeQuery(query).then(_logSuccess, _queryFailed); を返します。
}

// 特定の請求書を更新する
関数 refreshInvoice(請求書) {
    // Todo: パラメータ エラー チェックを追加しますか?
    var query = Breeze.EntityQuery.fromEntities([請求書]);
    manager.executeQuery(query).then(success, _queryFailed); を返します。

    関数の成功(データ) {
        _logSuccess(データ);
        データを返します。結果[0]; // クエリは配列を返します。呼び出し元は最初を望んでいます。
    }
}

関数 clearCachedInvoices() {
    var cachedInvoices = manager.getEntities('Invoice'); // キャッシュ内のすべての請求書
    // Todo: これは Breeze EntityManager 自体の関数である必要があります
    cachedInvoices.forEach(関数 (エンティティ) { manager.detachEntity(エンティティ); });
}

キャッシュのクリアに関する重要な注意事項

最初にキャッシュをクリアする理由は、以前に取得した請求書の一部を別のユーザーが削除した可能性があるためです。ユーザーが現在の請求書のみを表示できるように、それらをキャッシュから削除する必要があると思います。

請求書を削除できない場合 (たとえば、請求書を「非アクティブ」とマークして「論理的な削除」を行った場合) は、このキャッシュ クリア手順は必要ありません (そして担当者が懸念します)。あらゆる種類の問題を引き起こすため、私は個人的に削除に非常に警戒しています。私はソフト削除を好みます。

UI が以前の請求書エンティティを保持していないことを確認するのはあなた次第です。あなたはマネージャーにやり直しを依頼しました。つまり、既存のすべての請求書エンティティ参照は、切り離されたエンティティを参照しています。クエリの後、キャッシュされたすべての請求書が新しいインスタンスになります。

キャッシュをクリアすることのもう 1 つの危険は、保留中のすべての請求書の変更が消去されることです。請求書の変更 (新規、更新、またはスケジュールされた削除) が保存されていない可能性がある場合は、このメソッドを実行しないでください。保存されていない変更が失われるのを防ぐために、ガード ロジックを追加することをお勧めします。そのロジックが正確に何であるかは、アプリケーション固有です。への呼び出しが含まれる可能性がありますmanager.hasChanges('Invoice')

請求書に関するすべてを常に更新すれば、参照が失われる心配はありません。

これらの制約は、簡単に満たすことができます。それらは、あなたが最初に言ったこととほとんど一致しています。あなたは本当にキャッシュしたくなかったのです。したがって、これは簡単なことです...上記のコードを使用するだけで、ほとんど苦労せずにキャッシュの利点が得られます。

ああ...しかし、エンティティオブジェクトを完全に置き換えるのではなく、実際にリフレッシュしたい人のことを考えずにはいられません。ユーザーが変更を保存していない間に更新したいのかもしれません。それでも、別のユーザーによって削除されたエンティティを削除したいと考えています。

まあ、私も彼女のレシピを持っています。

関数 refreshAllInvoices(削除) {
        // 削除されたのは、エンティティで埋められるべき呼び出し元の配列です
        // キャッシュから削除します。以下の成功メソッドに入力されます。
    var cached = manager.getEntities('Invoice'); // キャッシュ内のすべての請求書を取得します
    return Breeze.EntityQuery.from('請求書')
                 .using(manager).execute(success, _queryFailed);

    関数の成功() {  
        削除されました。長さ = 0; // 配列をクリア  
        var 結果 = data.results; // クエリの結果
        // 「キャッシュされた」配列から各結果を削除します
        results.forEach(関数 (エンティティ) {
            var ix = cached.indexof(エンティティ);
            if (ix > -1) { cached[ix] = null; }
        });
        // 残っているものはサーバー上で削除されている必要があります
        // または、まだ保存していない新しいエンティティです
        // ループして、削除されたと思われるものを切り離します。
        cached.forEach(関数 (エンティティ) {
            if (エンティティ !== null &&
                !entity.entityAspect.entityState.isAdded()) {
                削除された.push(エンティティ); // 呼び出し元にこれを知らせる
                manager.detachEntity(エンティティ);
            }
        });

        結果を返します。
    }
}
于 2013-11-01T18:05:25.407 に答える