EF DbSet.Find抛出InvalidOperationException

4
我有两个实体,它们通过 TPT 继承模式相连接:
public class User {...}
public class Employee : User {...}

如您所见,基类不是抽象的,因此两种实体类型都可以添加到数据库集中。有两个独立的集合(我需要它们都在我的模型中):

public DbSet<User> Users { get; set; }
public DbSet<Employee> Employees { get; set; }

因此,Users表包含所有实体,而Employees仅包含那些被实例化为new Employee()的对象的附加数据。

现在,当我尝试使用Find方法从Employees集合中获取实体时,我期望它只会返回“实际”的员工。但是,如果我指定User实体的Id,EF仍然会从数据库中获取它,然后抛出一个InvalidOperationException异常:

“指定的从已实现类型'System.Data.Entity.DynamicProxies.User_B2E5EC989E36BE8C53B9285A70C4E879F0B5672E1D141B93FD299D1BA60258EE'到'Data.Employee'的转换无效。”

很明显不能将User强制转换为Employee。

我的问题是 - 是否有一种方法可以配置TPT继承,使得当处理不存在的Id时就像传递不存在的Id一样,Find方法只返回null。

我的当前解决方案是:

public Employee GetEmployeeById(int id)
{
    try
    {
        return Employees.Find(id);
    }
    catch(InvalidOperationException ex) when (ex.Message.StartsWith("The specified cast from a materialized"))
    {
        return null;
    }
}

但我不喜欢它的外观 - 所以也许有一个更好(更优雅)的解决方案?


TPT并不意味着你暴露了2个DbSet。它意味着你有一个DbSet<User>,该集合在数据库中使用TPT层次结构进行拆分。然后,你应该使用OfType<Employee>()仅查询Employee - haim770
在这种情况下,我不能使用Find()。据我理解,Find的性能结果比First/SingleOrDefault()更好。 - drty
尝试使用 this.Set<Employee>().Find(id); - haim770
Set<Employee>() 是在第一次实例化 DbSet<Employee> 对象时使用的。它与我当前使用的有何不同? - drty
它可能会有所不同,因为它是动态创建的。也许您当前静态定义的“Employees”属性的行为与“Set<Employee>()”不同,但可能性接近于零。 - haim770
2个回答

0

您缺少 DbContext 实例。因为那是声明,所以无法在表类型上进行搜索。

var checkfind = dbInstance.Employees.Find(searchedID);

如果您无法直接访问您的数据库,则可以使用

    using (DBLocal db = new DBLocal())
{
    db.Employees.Find(searchedID);
}

0

我倾向于使用singleordefault()/firstordefault()而不是find,因为如果没有找到匹配项,它会直接返回null,但你能否像这样在Find中使用谓词?

return Employees.Find(em => em.id == id && em is Employee);

Find() 只能以主键值作为参数。没有其他重载。 - drty
当然!dbSet!你可以使用Cast<User>()先将其转换为基本对象。 - Christopher Townsend

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接