3

私は VS2010 .Net4 Linq-to-EntityFramework を使用しており、子データを明示的に熱心にロードしたいと考えています。Linq-to-SQL IIUC では使用できますが、Linq-to-EF では使用できないDataLoadOptionsまたはLoadWithと同様の機能を提供したいと考えています。

(余談ですが、これは後でテスト中に再生するデータを記録できるようにするためです。遅延読み込みを使用しており、これらの発生を見つけて熱心な読み込みに置き換える必要があります。DataLoadOptionsメソッドを使用すると、これを実装するクリーンな方法が可能になります。 .)

MosesOfEgypt ブログで説明されているように、タイプセーフな熱心な読み込みスキームを提供しようとしています。T4 の世代を変更しましたが、最後の問題だと思います。.Net4 では、エンティティ プロパティはObjectSetを返します。しかし残念なことに、Include関数はObjectSetの基本クラスであるObjectQueryを返します。

以下は、変更された 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

「 * 」で始まる行は、 ObjectQueryからObjectSetへのキャストが行われる場所です。そして、これは無効なアップキャストであるため、設計時に明示的にキャストすると、間違っていない限り、実行時に失敗します。

1 つの解決策は、 ObjectSet.Includeの拡張メソッドを作成して、 ObjectQueryではなくObjectSetを返すようにすることです。可能であれば、 ObjectQuery.Include関数のソース コードを見つける方法を知りたいです。そして、これらのソリューションが機能するかどうかはわかりません。

また、Include関数の結果をObjectQueryからObjectSetにアップキャストする方法があったかどうかも疑問です。繰り返しますが、これが機能するかどうかはわかりません。

.Net4 での Linq-to-EF の DataLoadOptions 機能の実装に関するヘルプをいただければ幸いです。

4

2 に答える 2

1

ここであなたが何を求めているのかははっきりしていません。

.IncludeObjectQuery<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 に答える