2011-10-26 13 views
1

人!Linq2Sqlはカスタムタイプを理解する方法を教えてください。

問題の「ドメイン:IUser, IAddressBook, ICommentなど」を示すインターフェイスが設定されているとします。次のようにIUserが定義されていることを前提としています。例えば、私は唯一の言及契約を利用し自分のアプリケーションで

public interface IUser : IAmIdentifiedEntity<int>, IHaveName 
{ 
    string FullName { get; set; } 
    string Email { get; set; } 
    bool ReceiveNotification { get; set; } 
} 

public interface IHaveName 
{ 
    string Name { get; set; } 
} 

を、:

public IUser GetUser(string userName) 
{ 
    return Warehouse.GetRepository<IUser>().GetAll() 
     .First(u => u.Name == userName); 
} 

あなたが見ることができるように

は、私がデータを取得するために、いくつかのゲートウェイを使用しています。リポジトリのメソッド GetAll()IQueryable<TEntity>を返すので、複雑なクエリを作成し、遅延読み込みのメリットをすべて利用することができます。私がそれを紹介したとき、私はLinq2Sqlのアプライアンスを将来考えました。

クライアントコードの開発中に、私たちはデータ記憶域の「メモリ内」実装を使用していました。だからすべてうまく動作します。しかし、今度はドメインをSQL Serverにバインドする必要があります。だから私はLinq2Sqlにすべてのインフラストラクチャを実装し始めました...そして、簡単な解決策(フレドリック・カールスセスのarticleからインスピレーションを受けた)が最初の例外を得たとき、私はそのアイデアのすべての悲しみを実現しました... IUserの:

public partial class USER : IUser 
{ 
    int IHaveID<int>.ID 
    { 
     get { return USERID; } 
    } 

    string IHaveName.Name 
    { 
     get { return USERNAME; } 
     set { USERNAME = value; } 
    } 

    string IUser.FullName 
    { 
     get { return USERFULLNAME; } 
     set { USERFULLNAME = value; } 
    } 

    // ... same approach for other properties 
} 

そしてここで - 例外:

Exception: System.NotSupportedException: 
    The member 'Data.IHaveName.Name' has no supported translation to SQL. 

は、これは明らかに例外である - Linq2Sqlプロバイダは、外部インタフェースを理解していないが、どのように私はそれを解決する必要がありますか?それはドメイン・インターフェースのすべての現在のコードの使用状況を破るため

Expression<Func<string>> IHaveName.Name 
{ 
    get { return (() => USERNAME); } 
    set { USERNAME = value(); } 
} 

しかも私は理由宗教的信念のExpression<Func<int>>intを交換することはできません:)

:私は次のようにLinq.Expressionを返すために、ドメインのインターフェイスを変更することはできません は

たぶん、私はIUser.SomePropertyのクエリ」ASTの呼び出しにスキップして、それが内側のサブASTだとそれを置き換えるためにカスタム式のビジターを書く必要があります...

は、あなたはそれに自分の考えを提供することはできますか?

UPDATE。ここでは、Repositoryの実装について書きます。私の例では

public IQueryable<TEntity> GetAll() 
{ 
    ITable table = GetTable(); 
    return table.Cast<TEntity>(); 
} 

protected ITable GetTable() 
{ 
    return _dataContext.GetTable(_implType); 
} 

TEntity <=> IUserと私はOPは似て問題を抱えているrelated questionを、見つけた2_implType <=> typeof(USER)

UPDATE:GetAll()ソースを見て、具体的なORMエンティティと、それはだ間にいくつかの橋を必要としますドメインエンティティ。興味深いものが見つかりましたthe answer:著者は、エンティティ間の変換を実行するexpression visitorを作成することを提案しました(ORM < =>ドメイン)。

+0

新しい提案がありますか? – ajukraine

答えて

0

私の問題を解決する方法を見つけたようです。今日私は素敵な "Linqを使用してアドバンストドメインモデルのクエリ"という名前のseries of postを発見しました。著者はエンティティを扱うためのより便利な(かなり)ラムダ構文をサポートする方法を提示します。そして、Expression Tree変換を使用します。だから私はこのアプローチに従います、そして、私が成功すれば私はもっと詳細な答えを投稿します(私のブログで)。

あなたはそのアイデアについてどう思いますか? Expression提供者の実装に時間を費やすべきでしょうか?

UPDATE。私はカスタム式vistiorで失敗しました。これは、式ツリーを通して多くの変換が必要です。だから私はすべてのLinqロジックを複雑なクエリと永続性管理をカプセル化した "ストレージ"クラスに移行することに決めました。

0

Nameの属性をColumn属性で飾ります。これはLinq2SQLで使用している他のタイプと同じです。

+0

'Name'を書いたときに' IHaveName'を意味しましたか? – ajukraine

+0

いいえ、私は名前、実際のクラスLinq2SQLは、プロパティを見つけることを意味します。 –

+0

...いくつかのケースでこの問題を回避するインターフェイスではなく、ベースクラスのプロパティ上にある可能性があります。 –

0

これはよく知られた問題です.SQL文字列コマンドにキャストできないロジックでIQueryableを実行しようとすると、LINQ-to-SQL自体がこのエラーをスローします。

この問題は、IQueryable - 遅延実行の性質のためにも発生します。次のように

あなたはのIQueryableの実行を強制することができます。

public IUser GetUser(string userName) 
{ 
    return Warehouse.GetRepository<IUser>().GetAll() 
     .AsEnumerable() 
     .First(u => u.Name == userName); 
} 

これは、あなたのドメインインターフェースはそのまま残ることができ、いずれかの実行時に何か問題を与えないことを保証します。

乾杯!

+2

IQueryableの遅延実行ではなく、AsEnumerable()で延期していますが、実行方法だけで動作するクエリエンジンは異なります。 Linq2SQLは、オブジェクト定義に固有​​ではないデータベースに対してどのように計算するかについての情報を必要とします。これはその周りを回りますが、テーブル全体の大部分またはすべてを常に要求のためにスキャンする必要があります。 –

+0

@ジョーハンナ:はい、そうです。私は.NET MVCで多くの作業をしています。そのため、このアプローチを使用してSQLの依存関係を持つアプリケーションレベルで問題のテーブルをキャッシュする方が簡単です。 column属性ではこの問題は解決されませんが、私が知っている他の唯一の代替案は、IQueryable の拡張機能で、追加のパラメータをデータベース経由で生成されたLINQ-to-SQLクラスのフィールドとして挿入します。 –

+0

したがって、30000人のユーザーがいて、一致するユーザーが最後のユーザーだった場合は、使用していないデータベースから29999ユーザーを取得しますか?テーブルをメモリにキャッシュすることもできますし、ユーザー名の辞書でキャッシュすることもできます。これにより、ほぼ一定の時間内にキャッシュを取得できますが、キャッシュの無効化に関するすべての問題が発生します。 –

0

ジェネリックを使ってみましたか? Linq to SQLは、式をSQLに変換できるように具体的な型を知る必要があります。

+0

まず、アプリケーションはLinq2Sqlクラスについて何も知らないので、 'GetRepository ()'のような式を見ることは不可能です... – ajukraine

+0

あなたはアプリケーションクラスをLinq2Sqlの型に変換することはできませんが、それはかなりわかりませんが、AutoMapperのようなツールは人生を楽にします。 – jrummell

関連する問題