2

スタディとシリーズの2つのテーブルがあります。シリーズはFKでスタディに戻されるため、1つのスタディには可変数のシリーズが含まれます。各シリーズアイテムにはDeleted、データベースから論理的に削除されたことを示す列があります。

Deleted含まれているすべてのシリーズが削除された場合にのみtrueを返すStudyクラスのプロパティを実装しようとしています。O / R Designerで生成されたクラスを使用しているので、Studyタイプのユーザーが変更可能な部分クラスに以下を追加しました。

public bool Deleted
{
    get
    {
        var nonDeletedSeries = from s in Series
                               where !s.Deleted
                               select s;
        return nonDeletedSeries.Count() == 0;
    }
    set
    {
        foreach (var series in Series)
        {
            series.Deleted = value;
        }
    }
}

これにより、「メンバー'PiccoloDatabase.Study.Deleted'にはSQLへの変換がサポートされていません」という例外が発生します。getを呼び出すこの単純なクエリが実行されると:

IQueryable<Study> dataQuery = dbCtxt.Studies;
dataQuery = dataQuery.Where((s) => !s.Deleted);
foreach (var study in dataQuery)
{
   ...
}

このhttp://www.foliotek.com/devblog/using-custom-properties-inside-linq-to-sql-queries/に基づいて、次のアプローチを試しました。

static Expression<Func<Study, bool>> DeletedExpr = t => false;
public bool Deleted
{
    get
    {
        var nameFunc = DeletedExpr.Compile();
        return nameFunc(this);
    }
    set
    {  ... same as before
    }
}

クエリを実行すると、SQLへの変換がサポートされていないという同じ例外が発生します。(ラムダ式のロジックはまだ関係ありません-例外を乗り越えようとしているだけです。)

SQLへの変換を可能にする基本的なプロパティまたは何かが不足していますか?この例外に関するSOの投稿のほとんどを読みましたが、私の場合にぴったり合うものはないようです。

4

2 に答える 2

1

LINQ-to-SQLのポイントは、エンティティがマップされており、データベースに相関関係がなければならないということだと思います。LINQ-to-ObjectsとLINQ-to-SQLを混在させようとしているようです。

SeriesテーブルのデータベースにDeletedフィールドがあり、Studyテーブルにはないが、論理的なStudy.DeletedをSQLに変換したい場合は、拡張機能が最適です。

public static class StudyExtensions
{
    public static IQueryable<study> AllDeleted(this IQueryable<study> studies)
    {
        return studies.Where(study => !study.series.Any(series => !series.deleted));
    }
}

class Program
{
    public static void Main()
    {
        DBDataContext db = new DBDataContext();
        db.Log = Console.Out;

        var deletedStudies = 
            from study in db.studies.AllDeleted()
            select study;

        foreach (var study in deletedStudies)
        {
            Console.WriteLine(study.name);
        }
    }
}

これにより、「削除されたスタディ」式がSQLにマッピングされます。

SELECT t0.study_id, t0.name
FROM study AS t0
WHERE NOT EXISTS(
    SELECT NULL AS EMPTY
    FROM series AS t1
    WHERE (NOT (t1.deleted = 1)) AND (t1.fk_study_id = t0.study_id)
)

または、実際の式を作成してクエリに挿入することもできますが、それはやり過ぎです。

ただし、SeriesもStudyもデータベースにDeletedフィールドがなく、メモリ内にある場合は、最初にクエリをIEnumerableに変換してから、Deletedプロパティにアクセスする必要があります。ただし、そうすると、述語を適用する前にレコードがメモリに転送され、コストがかかる可能性があります。つまり

var deletedStudies = 
    from study in db.studies.ToList()
    where study.Deleted
    select study;

foreach (var study in deletedStudies)
{
    Console.WriteLine(study.name);
}
于 2012-07-26T17:21:51.983 に答える
0

クエリを実行するときExpressionは、プロパティではなく、静的に定義されたものを使用する必要があります。

事実上、代わりに:

dataQuery = dataQuery.Where((s) => !s.Deleted);

Linq to SQLクエリを作成するときはいつでも、代わりに次のものを使用する必要があります。

dataQuery = dataQuery.Where(DeletedExpr);

DeletedExprこれには、から見ることができる必要があることに注意してください。そのdataQueryため、クラスから移動するか、公開する必要があります(つまり、作成しpublicます。この場合、クラス定義を介してアクセスします:) Series.DeletedExpr

また、Expression関数本体を持つことができないという制限があります。したがって、DeletedExpr次のようになります。

public static Expression<Func<Study, bool>> DeletedExpr = s => s.Series.Any(se => se.Deleted);

プロパティは単に便宜上追加されているため、コードを複製することなく、コードオブジェクトの一部として使用することもできます。

var s = new Study();
if (s.Deleted)
    ...
于 2014-03-12T21:11:37.077 に答える