次の2つのクラスがあります。
public class Reward
{
public int Id { get; set; }
public int CampaignId { get; set;
public virtual Campaign Campaign { get; set; }
}
public class Campaign
{
public int Id { get; set; }
public virtual ICollection<Reward> Rewards { get; set; }
}
これにより、DbContextやマッピングなど、明らかに必要なものがすべて揃っています。
ここで、Rewardエンティティを作成して、次のように挿入するとします。
var reward = new Reward { CampaignId = 1 };
context.Set<Reward>().Add(reward);
context.SaveChanges();
reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id);
//reward.Campaign is null
Id 1のキャンペーンがあるのは明らかなので、FK制約は満足です。この挿入後、報酬エンティティには新しいIDが設定されます。問題は、報酬がまだ私が作成した報酬エンティティに過ぎないことです。これにより、reward.Campaignプロパティはnullになります。 EFは挿入されたエンティティをメモリに保持しているようで、.SingleOrDefault(a => a.Id ==報酬.Id)を実行すると、新しいプロキシではなく、単にメモリ内のエンティティを返します。これはおそらく良いことです。
したがって、質問は次のとおりです。挿入した後、またはナビゲーションプロパティをプロキシとして持つ新しいプロキシを取得した後に、ナビゲーションプロパティにアクセスまたはロードする方法。
私はおそらく間違った方法で挿入していますか?
私があなたを正しく理解していれば、外部キープロパティを介して関係を確立した後、複雑なプロパティを熱心にロードしようとしています。
SaveChanges()
は、複雑なプロパティをロードする方法では何もしません。新しいオブジェクトを追加する場合、多くても主キープロパティを設定します。
reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id);
行もCampaign
をロードする方法では何もしません。これは、報酬オブジェクトがコンテキストに関連付けられていないためです。 explicitlyEFにその複雑なオブジェクトをロードするかアタッチして、遅延ロードに魔法をかける必要があります。
したがって、context.SaveChanges();
の後、_reward.Campaign
_をロードするための3つのオプションがあります。
Attach()
コンテキストに報酬を与え、Campaign
を遅延ロード(アクセス時にロード)できるようにする
_context.Rewards.Attach(reward);
_
注:コンテキストのスコープ内で_reward.Campaign
_のみを遅延ロードできるため、コンテキストライフスパン内のプロパティにアクセスしない場合は、オプション2または3を使用します。
手動でLoad()
Campaign
プロパティ
_context.Entry(reward).Reference(c => c.Campaign).Load();
_
手動でInclude()
Campaign
プロパティ
_reward = context.Rewards.Include("Campaigns")
.SingleOrDefault(r => r.Id == reward.Id);
_
ただし、Load
が既にメモリにあるので、reward
をお勧めします。
詳細については、 this msdn doc の関連オブジェクトのロードセクションをご覧ください。
reward
オブジェクトをnew Reward()
として作成しているため、EFにはプロキシがありません。代わりに、次のようにDbSet.Createを使用して作成します。
var reward = context.Set<Reward>().Create();
reward.CampaignId = 5;
context.SaveChanges();
次に、DbSetに添付します。
context.Rewards.Attach(reward);
最後に、遅延読み込みを使用して関連エンティティを取得できるようになりました。
var campaign = reward.Campaign;
私は問題の簡単な解決策を持っています。
キャンペーンIDを報酬に追加する代わりに、キャンペーンオブジェクトを追加します。
var _campaign = context.Campaign.First(c=>c.Id == 1);//how ever you get the '1'
var reward = new Reward { Campaign = _campaign };
context.Set<Reward>().Add(reward);
context.SaveChanges();
//reward.Campaign is not null
ここでは、エンティティフレームワークがすべての面倒な作業を行います。
おそらく、Campaignオブジェクト全体をロードするのは無駄だと考えているのでしょうが、それを使用する場合(見た目はあなたのようです)、なぜそうなのかわかりません。キャンペーンオブジェクトからナビゲーションプロパティにアクセスする必要がある場合は、上記のフェッチ時にincludeステートメントを使用することもできます...
var _campaign = context.Campaign.include(/*what ever you may require*/).First(c=>c.Id = 1);
Include()
を使用してみましたか?このようなもの:
reward = context.Set<Reward>().Include("Campaigns").SingleOrDefault(a => a.Id == reward.Id);
Carrie KendallおよびDavidGに加えて(VB.NETの場合):
Dim db As New MyEntities
Dim r As Reward = = db.Set(Of Reward)().Create()
r.CampaignId = 5
db.Reward.Add(r) ' Here was my problem, I was not adding to database and child did not load
db.SaveChanges()
次に、プロパティr.Campaign
利用可能です