实体框架 6 - 一到可选关系

本文关键字:关系 框架 实体 | 更新日期: 2023-09-27 18:32:04

我对 EF 相当陌生并使用版本 6,并且停留在一对一的关系上。我的整体结构是我有一个 Gallery 对象,它里面有一个 GalleryMediaItem 实体的 ICollection,每个 GalleryMediaItem 都有一个与之关联的 MediaItem 实体。请注意,GalleryMediaItem 实体要求基础 MediaItem 具有值,尽管 MediaItem 实体本身不知道 GalleryMediaItem,这是有意为之的,因为 MediaItem 实体可以绑定到 GalleryMediaItem 以外的其他内容。下面是一个示例:

Gallery
    ---> ICollection<GalleryMediaItems>
             ---> [other properties]
             ---> MediaItem [has no knowledge of GalleryMediaItem]

正在尝试做的是在我从GalleryMediaItem实例访问 MediaItem 属性时让延迟加载为 MediaItem 实体工作。我的数据库结构与上面的代码结构匹配(GalleryMediaItem 有一个 GalleryId 和一个 MediaItemId,但 MediaItem 没有 GalleryMediaItemId,也不应该),并且返回的对象始终为 null。这里的奇怪部分是我的GalleryMediaItem实例上的MediaItemId属性已正确填充,但导航属性本身不起作用。我已经尝试了以下每种变体,但没有运气:

HasRequired(p => p.MediaItem).WithOptional();
HasRequired(p => p.MediaItem).WithMany();

等等。我尝试过的每个变体都没有收到任何错误,只是没有导航属性访问权限。

配置

它的正确方法是什么,其中GalleryMediaItem可以填写子实体MediaItemMediaItem本身(通过 POCO 和在数据库中)不知道父所有者?

编辑

其中一条评论要求我显示用于检索单个项目的代码。我有一个通用框架位于我的 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泛型只是一个超级基本的POCO,上面有Id,CreateDate,MaintDate等东西。我的所有 POCO 类都没有使用其相应数据库值的属性,一切都通过流体 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);
    }

实体框架 6 - 一到可选关系

如果你使用

HasRequired(p => p.MediaItem).WithMany();

您应该显示外键属性:

HasRequired(p => p.MediaItem).WithMany().HasForeignKey(p=>p.MediaItemId);

In HasRequired(p => p.MediaItem)。WithOptional();您还应该显示外键,但在这种情况下,您可以使用 ForeignKeyAttribute 或方法 Map