2016-04-09 8 views
0

を私はナビゲーションプロパティが取得する以下のコードIブランチを使用して支店内の項目をロードしようとするたびに、私はナビゲーションプロパティはロードされません - EF

public class Items 
{ 
    public int Id { get; set; } 
    public string Barcode { get; set; } 
    public string Name { get; set; } 
    public int SizeId { get; set; } 
    public int Price { get; set; } 
    public int DiscountId { get; set; } 
    public int ShortageMargin { get; set; } 
    [NotMapped] 
    public double ActualPrice 
    { 
     get 
     { 
      double amount = ((double)Price * (double)Discount.Amount/100); 
      double price = (Price - amount < 0) ? 0 : Price - amount; 
      return price; 
     } 
    } 

    public Discounts Discount { get; set; } 
    public ItemSizes Size { get; set; } 
    public ICollection<ItemsInBranches> ItemsInBrach { get; set; } 
} 

public class Branches 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Location { get; set; } 

    public ICollection<Employees> Employees { get; set; } 
    public ICollection<TransactionLog> TransacionLogs { get; set; } 
    public ICollection<ItemsInBranches> ItemsInBranch { get; set; } 
} 

public class ItemsInBranches 
{ 
    public int Id { get; set; } 
    public int ItemId { get; set; } 
    public int BranchId { get; set; } 
    public int Amount { get; set; } 

    [NotMapped] 
    public bool IsShort 
    { 
     get 
     { 
      return Amount < Item.ShortageMargin; 
     } 
    } 

    public Items Item { get; set; } 
    public Branches Branch { get; set; } 
} 

を次のように定義された3つのモデルのアイテム、枝とItemsInBranchesを抱えていますうまくロードされたが、私のアイテムは常に

public IEnumerable<StorageViewModel> GetStorage(int? BranchId) 
    { 
     var storage = Find(x => true).Select(s => new StorageViewModel 
     { 
      Amount = s.Amount, 
      BranchName = s.Branch.Name, 
      ItemName = s.Item.Name, 
      SortageMargin = s.Item.ShortageMargin, 
      IsShort = s.IsShort 
     }); 
     return storage; 
    } 

    public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate) 
    { 
     return _dataContext.Set<TEntity>().Where(predicate); 
    } 

私はアイテムIDとBranchIdは、データベース内のアイテムや支店のテーブルの外部キーに設定されていることを確認しましたがnullに設定されている、彼らはNULLを許可していないと、彼らは強制します外部キー制約 cou私が教えてくれるのは、なぜアイテムが常にnullに設定されている間にブランチだけがロードされるのかです。

+0

万一、簡潔にするためにコンストラクタコードを削除しますか? –

+0

ItemNameとSortageMarginがnullであることを意味しますか? – Evk

+0

現時点では、それぞれの「ItemsInBranches」のデータベースから関連エンティティ(ブランチ、アイテム)を別々にフェッチするために、遅延ロードに頼っています。両方のプロパティは 'virtual'ではないので、' Branch'はロードされているように見えますし、 'Item'はロードしないことに驚いていません。しかし、投影を両方とも有効にして有用にする(つまり、データの量を制限する)ために、 'Find'から' IQueryable'を返すべきです。後で 'IsShort'を扱う –

答えて

2

通常、私はあなたがFindメソッドでやっているようなヘルパーメソッドを使ってフレームワークをラップしようとしないでください。そのため、あなたはこの問題にぶち当たっています(そうでなければ、ヘルパーなしで解決しなければならないよりも、ソリューションを難しくしています)。

あなたはこの問題あなたに走った(または、あなたの Find一日で AsNoTracking()を指定したい場所を ChangeTrackerを知ると、それがどのように動作するかと SaveChanges()開始が遅い実行しているか、あなたが大きいためメモリフットプリントを持っているときに実行することがあり

もちろん、これはEFで問題になります。トランザクションのような重要な概念(抽象化しようとしているレイヤーの詳細...)を実際に理解することなく、人々が開発するのが簡単すぎるからです。

何らかの方法で関連エンティティを読み込む必要があります。 I'd recommend reading this link and choosing an option.あなたのGetStorageメソッドにしか触れないリンクには、問題を簡単に解決できるオプションが1つありますが、多くのレコードがあるとパフォーマンスが良いとは限りません。たくさんあります。私は、あなたのコードをもっと見ることなく、あなたに良い推薦を与えることはできません。他のものをロードしていて、他のものがロードされていない場合、それらは同じである(同じヌル入力可能なFKで、対応するレコードがある)場合は、おそらくどこかの構成だと思います。これは多分SELECTステートメントを生成することに注意してください。私は、GetStorageの中にFindを使用して、あなたが必要としていないレコードをつかむために、より良い方法(Set<>に落ちる以外に)を考えることができませんでした。 TEntityが異なる別のクラスからFindを呼び出すことができれば、1つのSELECTステートメントで必要とするレコードはItemsになる可能性がありますが、サービスとそのライフサイクルの設定方法はわかりません。これは、パフォーマンスと、データアクセスラッパーの一括リファクタリングがないという妥協点です。

var allEntities = Find(x => true).ToList(); 
allEntities.ForEach(x => _dataContext.Entry(x).Reference(y => y. Item).Load()); 
var storage = allEntities.Select(s => new StorageViewModel 
// ... 

GetStorageそれは1 TEntityに固有のように思えます。あなたのFindメソッドはTEntityが包含クラスのジェネリックとして定義されているようです - もしそれらを背中合わせに入れても(2)異なるクラスにあると推測しなければなりません。あなたのFindメソッドはおそらくEFを抽象化してデータベースへの「より単純な」インターフェースを提供するクラスにあります。 EFは既にデータベースとの簡単なインターフェースです。あなたは別のものを必要としません。

あなたが代わりにやっている可能性がありモックする必要があろう(あなたのリポジトリへの依存を取るのいずれかあなたのドメインロジックを持つ、特定TEntity年代にハード依存関係を取り、DbContextに依存し、具体的なリポジトリを作っていますレポジトリがドメインロジックから完全に分離されているため、疑似データベース、実際のデータベース、またはリーキーなメモリ内のデータベースを使用してドメインロジックをテストすることができます)。その後、リポジトリはアプリケーションの残りの部分をEFから保護しているので、ADO.NETやDapperのような軽いORMに変更することができます。

Findこのような方法は、EF抽象化です。あなたが気付いていなくても、EF(そしておそらくあなたのスキーマ)に依存しています。私が簡単に説明したのは、データベースの抽象化です。実際には、必要に応じてデータアクセス(およびスキーマ)を変更できるようになります。APIや動作を変更せずにリポジトリの実装を変更するだけです...

+0

ここであなたが言っていることは事実かもしれませんが、OPは建築的レビューを求めていませんでした。それを無料で追加しても大丈夫ですが、直接質問にも適切に対処する必要があります。 OPの問題は予測に含まれているので、「Include」はここでは役に立たない。 –

+0

@GertArnoldあなたの言ったことに同意しました。私はその質問に答えたと思って、最初に問題を抱えている(なぜなら、コーナーに自分自身をコーディングしている)OPがなぜその状況にあるのかを説明しようとしていた。 'Find'を呼び出すと' DbSet <> 'ではなく 'IEnumerable <>'がありますので、その時点で 'Include'を呼び出すのは遅すぎます。 OPは別のクエリとなることができると思いますが、もしOPが "GetStorage"内でのみ起こる "修正"を望むなら、私はそれを私の答えに加えることができます。 –

+0

@GertArnold申し訳ありません。私は自分の答えを編集しました。あなたが与えるより建設的なフィードバックがあれば、私はそれを感謝します! –