DbSet.FirstOrDefault()?
本文关键字:FirstOrDefault DbSet | 更新日期: 2023-09-27 18:15:25
我试着这样做但是它说我不能使用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'的定义,也没有扩展方法'FirstOrDefault'接受类型为'System.Data.Entity '的第一个参数。
可以找到DbSet'(您是否缺少using指令或汇编引用?)我然后尝试了这个Cast
方法,但给出了一个错误不能从非通用DbSet创建一个DbSet类型的对象'WindowStyle' (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; }
}
也许你错过了
using System.Linq;
这个答案可能对你没有帮助,这取决于你调用这个方法的情况有多"动态",基本上如果你在编译时知道类型与否。如果你知道它,你可以写一个泛型方法:
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,则不需要加载完整实体。您可以让数据库来选择属性,从而略微提高性能。如果在数据库中没有匹配的名称,我还返回一个可空的int。
你可以在你的代码中这样调用它:
int? id = db.GetId<WindowStyle>("abc");
如您所见,对于这个解决方案,您必须在编译时指定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();
}
}
并命名为:
int? id = db.GetId("abc", someType);
如果someType
没有从DomainEntity
继承,它将在运行时抛出异常。泛型版本将在编译时对此进行检查。所以,如果你可以选择第一个版本
第一个构造不能工作,因为您正在使用非泛型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;
}
您可能担心不同类型之间的名称冲突,但您可能可以从这个开始,并查看派生类型关联,以验证您正在查看正确的类型。处理此问题的一种方法是在DomainEntity定义中添加类型标志。
问题来了。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;
这是我的一个想法,似乎是有效的。
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;
}
试着反转一下
<>之前集。Where(x => x. name == name).Select(o=> x. id).FirstOrDefault();之前您的将返回一个空实体,然后尝试从中获取Id。