私はEFにかなり慣れておらず、バージョン6を使用しており、1対1の関係に固執しています。私の全体的な構造は、内部に GalleryMediaItem エンティティの ICollection を持つ Gallery オブジェクトがあり、各 GalleryMediaItem にはそれに関連付けられた MediaItem エンティティがあります。GalleryMediaItem エンティティには、基礎となる MediaItem に値があるという要件があることに注意してください。ただし、MediaItem エンティティ自体は GalleryMediaItem を認識していません。これは、MediaItem エンティティが GalleryMediaItem 以外のものに関連付けられる可能性があるため、意図的なものです。次に例を示します。
Gallery
---> ICollection<GalleryMediaItems>
---> [other properties]
---> MediaItem [has no knowledge of GalleryMediaItem]
私がやろうとしているのは、インスタンスMediaItem
からプロパティにアクセスするときに、MediaItem エンティティに対して遅延読み込みを機能させることです。GalleryMediaItem
私のデータベース構造は上記のコード構造と一致し (GalleryMediaItem には GalleryId と MediaItemId がありますが、MediaItem には GalleryMediaItemId はありませんし、そうすべきでもありません)、返されるオブジェクトは一貫して null です。ここでの奇妙な点はMediaItemId
、インスタンスのプロパティGalleryMediaItem
が正しく設定されているのに、ナビゲーション プロパティ自体が機能しないことです。次のすべてのバリアントを試してみましたが、うまくいきませんでした。
HasRequired(p => p.MediaItem).WithOptional();
HasRequired(p => p.MediaItem).WithMany();
等々。試したすべてのバリアントでエラーが発生することはありません。ナビゲーション プロパティにアクセスできないだけです。
GalleryMediaItem
子MediaItem
エンティティを入力できるがMediaItem
、それ自体では (POCO 経由とデータベースの両方で) 親所有者の知識がない場合に、これを構成する適切な方法は何ですか?
編集
コメントの 1 つで、個々のアイテムを取得するために使用されているコードを表示するよう求められました。DbContext インスタンスの上に汎用フレームワークがありますが、その下には単一のGallery
エンティティを取得するためのメソッドがあります。
/// <summary>
/// Retrieves an entity based on the Id parameter.
/// </summary>
/// <typeparam name="E">The type of BaseEntity being retrieved.</typeparam>
/// <param name="Id">The Id to retrieve.</param>
/// <returns>A BaseEntity of type E if a match is found, otherwise null.</returns>
public virtual E GetById<E>(long Id)
where E : BaseEntity
{
var whereClause = DataUtilities.BuildOrExpressionTree<E, long>(new long[] { Id }, entity => entity.Id);
IQueryable<E> entities = this.GetTable<E>().Where(whereClause);
if (entities.Count() == 1)
return entities.First();
else
return null;
}
上記のBaseEntity
ジェネリックは、Id、CreateDate、MaintDate などを含む超基本的な POCO です。私の POCO クラスはいずれも、対応する DB 値の属性を使用せず、すべてが流動的な EF API を介して行われます。Gallery
直接継承するBaseEntity
ため、この汎用関数は期待どおりに機能します。
関数は次のDataUtilities.BuildOrExpressionTree
ようになります。
public static Expression<Func<TValue, bool>> BuildOrExpressionTree<TValue, TCompareAgainst>(IEnumerable<TCompareAgainst> list, Expression<Func<TValue, TCompareAgainst>> convertBetweenTypes)
{
ParameterExpression inputParam = convertBetweenTypes.Parameters[0];
var binaryExpressionTree = BuildBinaryOrTree(list.GetEnumerator(), convertBetweenTypes.Body, null);
return Expression.Lambda<Func<TValue, bool>>(binaryExpressionTree, new [] { inputParam });
}
private static Expression BuildBinaryOrTree<T>(IEnumerator<T> itemEnumerator, Expression expressionToCompareTo, Expression expression)
{
if (itemEnumerator.MoveNext() == false)
return expression;
ConstantExpression constant = Expression.Constant(itemEnumerator.Current, typeof(T));
BinaryExpression comparison = Expression.Equal(expressionToCompareTo, constant);
BinaryExpression newExpression;
if (expression == null)
newExpression = comparison;
else
newExpression = Expression.OrElse(expression, comparison);
return BuildBinaryOrTree(itemEnumerator, expressionToCompareTo, newExpression);
}