18

これはlinq-to-sqlです

私は多くの異なるクラスがすべて同じクエリを実行していますが、結果の投影は少し異なります。理想的には、クエリを1か所にまとめて、プロジェクションをSelectメソッドに渡せるようにしたいと思います。コンクリートタイプの場合は正常に機能します。

public void GetResults() {
    var junk = db.SiteProducts.Select(Project());
}

public Expression<Func<DbEntities.SiteProduct, string>> Project() {
    return p => p.ProductAlert;
}

しかし、匿名タイプを返そうとすると失敗します

public void GetResults() {
    var junk = db.SiteProducts.Select(Project());
}

public Expression<Func<DbEntities.SiteProduct, TResult>> Project<TResult>() {
    return p => new { p.ProductAlert };
}

2番目のケースでジェネリック型推論が失敗する理由を完全に理解しています。しかし、自分の表現をゼロから作成する以外に、これを機能させるための秘訣はありますか?

4

4 に答える 4

4

これは興味深い質問です。DTOはここであなたを助けることができると思いますが、注意すべき制限と落とし穴があります。次のLINQPadの例を見てください。

class ProjectDTO
{
    public string Name { get; set; }

    public static Expression<Func<Project, ProjectDTO>> ToDTO = (e) => new ProjectDTO
    {
        Name = e.Name
    };

    public ProjectDTO() {}

    public ProjectDTO(Project project)
    {
        Name = project.Name;
    }
}

void Main()
{
    Projects.Select(p => p.Name).Dump();
    Projects.Select(ProjectDTO.ToDTO).Dump();
    Projects.Select(p => new ProjectDTO(p)).Dump();
}

生成されたSQL:

SELECT [t0].[Name]
FROM [Project] AS [t0]
GO

SELECT [t0].[Name]
FROM [Project] AS [t0]
GO

SELECT [t0].[ProjectId], [t0].[Name], [t0].[Description], [t0].[DateCreated], [t0].[DateModified], [t0].[DateComplete], [t0].[CreatedBy]
FROM [Project] AS [t0]

ご覧のとおり、コピーコンストラクターを使用してDTOのプロパティを割り当てることはできません。これにより、オブジェクト全体がデータベースから強制的に引き戻されます。

これは、ベースDTOを拡張し、データのより特殊なビューのプロパティを追加する場合にもわずかに制限されます。つまり、同様のコードを持つ複数の式が作成される可能性があります。

ただし、オプション2は非常に気に入っていますが、このオプションは単一タイプのプロジェクションに制限されている可能性が高いと確信しています。次の例を検討してください。

var query = from p in Projects
            join t in Tasks on p.ProjectId equals t.ProjectId
            select ProjectDTO.ToDTO; //Can't be used like this

このタイプのクエリ構文では式を使用できないと思います。一般的に言って、私は全面的に機能する解決策はないと思います。クエリに常に含めることが非常に安価なプロパティのいくつかに基づいて、より少ない投影を提供できるかどうかを確認するために、設計を確認する必要がある場合がありますか?

動的LINQライブラリを使用したり、式ツリーを手動で構築したりせずに、LINQ-SQL/LINQ-Entitiesを使用して動的選択を作成できるかどうかも確認したいと思います。

于 2012-03-17T14:01:17.027 に答える
2

これはコンパイル時に機能しません。動的なものを使用すると、もちろんそれを機能させることができます。

簡単な解決策は、匿名型ではなく、カスタムメイドのDTOクラスを使用することです。このようなDTOクラスは、ほんの数行しかかからず、保守も簡単です。通常、これは良い解決策です。

于 2012-03-16T23:03:28.090 に答える
2

IdeaBladeには、ProjectionSelector予測を抽象化するために使用できるクラスがあります。射影クエリを作成する必要があるが、コンパイル時に関係する型がわからない場合は、ProjectionSelectorクラスのインスタンスを作成し、実行時に型情報を渡すことができます。

クラスとサンプルコードは、次の場所にあります。

動的な「Select」、「SelectMany」、および「GroupBy」句を作成します
http://drc.ideablade.com/xwiki/bin/view/Documentation/dynamic-projection

于 2012-03-16T20:45:58.803 に答える
2

私があなたの質問を正しく理解しているなら、あなたはこのコードを使うことができます:

まず、次のようにデータを選択するためのメソッドを宣言します。

public List<TResult> FindAll<TResult>(Func<Regions, TResult> selector) where TResult : class
    {
        using (RepositoryDataContext = new DataClasses1DataContext())
        {
                return RepositoryDataContext.Regions.Select<Regions, TResult>(selector).ToList<TResult>();

        }
    }

次に、次のようにselectステートメントを作成できます。

Func<Regions, SelectAllRegion> select = r => new SelectAllRegion
        {
            RegionID = r.RegionID,
            RegionDescription = r.RegionDescription
        };

私のSelectAllRegion

 public class SelectAllRegion
{
    public SelectAllRegion()
    {
    }
    public int RegionID { get; set; }
    public string RegionDescription { get; set; }
}

地域はRegionノースウィングのテーブルです。これがお役に立てば幸いです。

于 2012-03-17T12:50:29.940 に答える