3

我正在使用 VS2010 .Net4 Linq-to-EntityFramework 并希望显式加载一些子数据。我想提供类似于DataLoadOptionsLoadWith的功能,这些功能可用于 Linq-to-SQL IIUC,但不适用于 Linq-to-EF。

(顺便说一句,这样我可以记录数据以便稍后在测试期间播放。我们使用了延迟加载,我需要找到这些事件并替换为急切加载。DataLoadOptions方法将允许一种干净的方式来实现这一点.)

我正在尝试提供一种类型安全的急切加载方案,如MosesOfEgypt 博客中所述。我已经修改了 T4 的一代,并且遇到了我认为是最后一个问题。在 .Net4 中,实体属性返回ObjectSet。但不幸的是,Include函数返回ObjectQuery,它是ObjectSet的基类。

这是从修改后的 T4 模板生成的 ObjectContext 类的子集:

    #region DataLoadOptions Functionality

            public DataLoadOptions LoadOptions { get; set; }

            private ObjectSet<TEntity> ApplyDataLoadOptions<TEntity>(string queryString) where TEntity : class
            {
                var query = CreateObjectSet<TEntity>(queryString);

                if (LoadOptions != null)
                {
                    var members = LoadOptions.GetPreloadedMembers<TEntity>();

                    foreach (var member in members)
                    {
 **********              query = query.Include(member.Name);
                    }
                }
                return query;
            }

    #endregion



    #region ObjectSet Properties

        /// <summary>
        /// No Metadata Documentation available.
        /// </summary>
        public ObjectSet<Address> Addresses
        {
            get
            {
                if ((_Addresses == null))
                {
                    _Addresses = ApplyDataLoadOptions<Address>("Addresses");
                }
                return _Addresses;
            }
        }

    #endregion

以“ * ”开头的行是从ObjectQueryObjectSet的转换发生的地方。而且这是一个无效的向上转换,因此如果在设计时显式转换,将在运行时失败,除非我做错了。

一种解决方案可能是为ObjectSet.Include编写扩展方法,以便它返回ObjectSet而不是ObjectQuery。如果可能的话,我想知道如何找到ObjectQuery.Include函数的源代码。而且我不确定这些解决方案是否有效。

还想知道是否有办法将Include函数的结果从ObjectQuery向上转换到ObjectSet。同样,不确定这是否可行。

任何有关在 .Net4 中为 Linq-to-EF 实现 DataLoadOptions 功能的帮助将不胜感激。

4

2 回答 2

1

目前还不清楚你在这里问什么。

.Include返回一个ObjectQuery<T>,它实现IQueryable<T>. 为什么要将其转换为ObjectSet<T>??

WRT“强类型” Include,简短的回答是你不能。但是你可以通过扩展方法的语法糖让它变得更甜。

我们为每个实体创建枚举(可能有点矫枉过正,但我​​讨厌魔术字符串),其中包含每个关联。我们的存储库接受这些枚举的数组。然后我们在枚举上使用扩展方法来转换为Include.

示例(简化)存储库代码:

public ICollection<Order> GetOrdersWithUser(Expression<Func<Order,bool>> predicate, OrderAssocations[] includes)
{
   return _ctx.Orders.WithAssociations(includes).Where(predicate).ToList();
}

和扩展:

public static ObjectQuery<Order> WithAssociations(this ObjectQuery<Order> source, OrderAssociations[] includes)
{
   var query = source;

   foreach (var include in includes)
   {
      query = query.Include(include.ToNavigationalProperty()));
   }

   return query;
}

.ToNavigationalProperty()是枚举的另一个扩展方法,它只返回匹配的 Navigational 属性。

于 2010-11-24T11:09:53.227 回答
0

不确定这是否回答了您的问题……但是,这是我完成“动态”急切加载的方式:

/// <summary>
    /// Flags to indicate which child entities to eager load
    /// </summary>
    [Flags]
    public enum IncludeFlags
    {
        None = 1,
        All = 1 << 1,
        ChildEntity1 = 1 << 2,
        ChildEntity2 = 1 << 3,
        ChildEntity3 = 1 << 4
    }

    /// <summary>
    /// Method to create my object query
    /// </summary>
    /// <param name="context">Database context</param>
    /// <param name="includeFlags">Indicates which flags to Include</param>
    /// <returns></returns>
    private static ObjectQuery<MyEntity> GetContext(DataBaseContext context, IncludeFlags includeFlags)
    {
        ObjectQuery<MyEntity> query = new ObjectQuery<MyEntity>("MyEntity", context);

        if ((includeFlags & IncludeFlags.None) != IncludeFlags.None)
        {
            bool getAll = ((includeFlags & IncludeFlags.All) == IncludeFlags.All);
            if (getAll || ((includeFlags & IncludeFlags.ChildEntity1) == IncludeFlags.ChildEntity1))
                query = query.Include("ChildEntity1");

            if (getAll || ((includeFlags & IncludeFlags.ChildEntity2) == IncludeFlags.ChildEntity2))
                query = query.Include("ChildEntity2");

            if (getAll || ((includeFlags & IncludeFlags.ChildEntity3) == IncludeFlags.ChildEntity3))
                query = query.Include("ChildEntity2.ChildEntity3");
        }

        return query;
    }

    public static MyEntity[] GetMyEntities(IncludeFlags flags = IncludeFlags.None)
    {
        DataBaseContext db = new DataBaseContext();
        from e in GetContext(db, flags)
        select e;

        return e.ToArray();
    }

    public void GetMyEntities()
    {
        MyEntity[] entities = Test.GetMyEntities(); // Does not load any child entities
        MyEntity[] entities2 = Test.GetMyEntities(IncludeFlags.All); // Loads them all
        MyEntity[] entities3 = Test.GetMyEntities(IncludeFlags.ChildEntity1 | IncludeFlags.ChildEntity2); // Only loads child 1 and 2
        MyEntity[] entities4 = Test.GetMyEntities(IncludeFlags.ChildEntity3); // Only loads ChildEntity2.ChildEntity3
    }

希望这可以帮助。

于 2010-11-23T20:00:58.387 回答