DbSet.FirstOrDefault()?

Ben*_*min 7 c# entity-framework entity-framework-4.1 dbcontext

我试图这样做,但它说我不能使用FirstOrDefault,

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

错误是' System.Data.Entity.DbSet'不包含'FirstOrDefault'的定义,并且没有可以找到接受类型'System.Data.Entity.DbSet'的第一个参数的扩展方法'FirstOrDefault'(你是否遗漏了) using指令或程序集引用?)

我然后尝试了这个Cast方法,但是给出了一个错误无法从非泛型DbSet为'WindowStyle'类型的对象创建一个DbSet(顺便说一下,WindowStyleDomainEntity下面继承),

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

这是班级,

public class DomainEntity
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

ris*_*res 24

也许你错过了

using System.Linq;
Run Code Online (Sandbox Code Playgroud)


Sla*_*uma 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我已将其更改为投影,因为如果您只需要Id,则无需加载完整实体.您可以让数据库完成工作以选择属性以稍微提高性能.如果数据库中的名称不匹配,我也返回一个可以为null的int.

您可以在代码中调用它,如下所示:

int? id = db.GetId<WindowStyle>("abc");
Run Code Online (Sandbox Code Playgroud)

正如您在此解决方案中所看到的,您必须WindowStyle在编译时指定类型.

这假设它DomainEntity不是模型的一部分(没有DbSet<DomainEntity>),而只是实体的基类.否则@Paul Keister的解决方案会更容易.

编辑

或者,您也可以尝试以下方法:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

并称之为:

int? id = db.GetId("abc", someType);
Run Code Online (Sandbox Code Playgroud)

如果someType不继承,它将在运行时抛出异常DomainEntity.通用版本将在编译时检查它.所以,如果你可以选择第一个版本.


Pau*_*ter 5

第一个构造将无法工作,因为您正在使用非泛型DbSet,因此您无法应用FirstOrDefault扩展方法,该方法仅适用于泛型.听起来你已经理解了,因为你已经在尝试获得非泛型的DbSet.使用Cast()方法获得的错误是由于您尝试将DbSet强制转换为DbSet引起的.这是不允许的,因为如果是这样的话,可以将不合格的成员添加到DbSet(除了WindowsStyle之外的类型的对象).另一种说法是DbSets不支持协方差,因为DbSets允许添加.

我想你必须找到另一种方法来做你想做的事情.以这种方式混合LINQ和继承显然是有问题的.由于您已定义了基本类型,并且您只使用基类型上可用的属性,为什么不只是查询基类型?

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

您可能担心各种类型之间的名称冲突,但您可以从此开始并查看派生类型关联以验证您正在查看正确的类型.解决此问题的一种方法是在DomainEntity定义中添加类型标志.