8

これを実行しようとしていますが、FirstOrDefaultを使用できないと表示されます。

public static int GetId(this Context db, Type type, string name)
{
    return db.Set(type).FirstOrDefault(x => x.Name == name).Id;
}

エラーはSystem.Data.Entity.DbSet」に「FirstOrDefault」の定義が含まれておらず、タイプ「System.Data.Entity.DbSet」の最初の引数を受け入れる拡張メソッド「FirstOrDefault」が見つかりませんでした(欠落していますか?使用ディレクティブまたはアセンブリ参照?)

次に、このCastメソッドを試しましたが、エラーが発生しました。タイプ'WindowStyle'のオブジェクトの非ジェネリックDbSetからDbSetを作成できません(btwは以下WindowStyleから継承しDomainEntityます)。

var set = db.Set(type).Cast<DomainEntity>();
return set.FirstOrDefault(x => x.Name == name).Id;

これがクラスです、

public class DomainEntity
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}
4

6 に答える 6

29

多分あなたは行方不明です

using System.Linq;
于 2013-04-28T15:35:49.087 に答える
8

基本的にコンパイル時に型がわかっているかどうかにかかわらず、このメソッドを呼び出す状況がどれほど「動的」であるかによっては、この回答は役に立たない可能性があります。あなたがそれを知っているなら、代わりに一般的なメソッドを書くことができます:

public static class MyExtensions
{
    public static int? GetId<TEntity>(this Context db, string name)
        where TEntity : DomainEntity
    {
        return db.Set<TEntity>()
            .Where(x => x.Name == name)
            .Select(x => (int?)x.Id)
            .FirstOrDefault();
    }
}

IDのみが必要な場合はエンティティ全体をロードする必要がないため、これをプロジェクションに変更しました。パフォーマンスを少し向上させるために、データベースにプロパティを選択する作業を行わせることができます。また、データベース内の名前に一致するものがない場合に備えて、null許容のintを返します。

次のように、コードでこれを呼び出すことができます。

int? id = db.GetId<WindowStyle>("abc");

このソリューションでわかるようにWindowStyle、コンパイル時にタイプを指定する必要があります。

DomainEntityこれは、がモデルの一部ではなく(存在しないDbSet<DomainEntity>)、エンティティの基本クラスにすぎないことを前提としています。そうでなければ、@PaulKeisterのソリューションの方が簡単です。

編集

または、次のことも試すことができます。

public static class MyExtensions
{
    public static int? GetId(this Context db, Type entityType, string name)
    {
        return ((IQueryable<DomainEntity>)db.Set(entityType))
            .Where(x => x.Name == name)
            .Select(x => (int?)x.Id)
            .FirstOrDefault();
    }
}

そしてそれを呼んでください:

int? id = db.GetId("abc", someType);

someTypeから継承しない場合、実行時に例外をスローしますDomainEntity。汎用バージョンは、コンパイル時にこれをチェックします。だから、もしあなた最初のバージョンを好むことができれば。

于 2011-11-22T19:34:29.350 に答える
5

非ジェネリックDbSetを使用しているため、最初の構成は機能しません。したがって、ジェネリックでのみ機能するFirstOrDefault拡張メソッドを適用することはできません。非ジェネリックDbSetを取得しようとしているので、すでに理解しているようです。Cast()メソッドで発生するエラーは、DbSetをDbSetにキャストしようとしたことが原因で発生します。不適合なメンバーをDbSet(WindowsStyle以外のタイプのオブジェクト)に追加することが可能であるため、これは許可できません。別の言い方をすれば、DbSetは追加を許可しているため、DbSetでは共分散はサポートされていません。

私はあなたがやろうとしていることをする別の方法を見つけなければならないと思います。このようにLINQと継承を混在させると、明らかに問題が発生します。基本タイプが定義されており、基本タイプで使用可能な属性のみを操作しているので、基本タイプを照会するだけではどうでしょうか。

    public static int GetId(this Context db, string name)
    {
        return db.DomainEntities.FirstOrDefault(x => x.Name == name).Id;
    }

さまざまなタイプ間の名前の衝突について心配しているかもしれませんが、おそらくこれから始めて、派生したタイプの関連付けを調べて、正しいタイプを見ていることを確認できます。これに対処する1つの方法は、DomainEntity定義にタイプフラグを追加することです。

于 2011-11-21T22:57:17.627 に答える
3

これが問題です。このDbSetクラスには、データベースタイプ(など)のみを許可する独自の実装がCast<T>()Cast<WindowStyle>()あるため、このメソッドは許可せずCast<DomainEntity>()、例外をスローします。

代わりに、IQueryable.Cast<T>()データを基本型にキャストするだけの拡張メソッドを使用する必要があります。次に例を示します。

var set = ((IQueryable)db.Set(type)).Cast<DomainEntity>();
return set.First(x => x.Name == name).Id;
于 2011-11-22T18:09:55.380 に答える
2

これが私が持っていたアイデアで、うまくいっているようです。

public static int GetId(this Context db, Type type, string name)
{
    var set = db.Set(type);
    foreach (dynamic entry in set)
        if (entry.Name == name)
            return entry.Id; 
}
于 2011-11-22T15:22:37.333 に答える
0

少し逆にしてみてください

set.Where(x => x.Name == name).Select(o => o.Id).FirstOrDefault();

nullエンティティを返し、そこからIDを取得しようとします。

于 2011-11-21T22:43:43.397 に答える