13

这是我的情况:我已经在 ASP.NET MVC 3 应用程序上工作了一段时间。它有一个数据库(由一个 db 项目构建;我将首先使用 db),为此我有一个 edmx 模型,然后是一组 POCO。我的实体在数据库中有复数名称,而 POCO 有单数名称。一切都很好地映射没有问题。

或者习惯了,直到我添加了一个新表(称为 TransactionStatuses)。现在所有旧实体仍然有效,但新实体却不行。当我尝试将它与相关实体一起加载时:

var transactions = (from t in db.Transactions.Include(s => s.TransactionStatus) //TransactionStatus - navigation property in Transactions to TransactionStatuses
                    where t.CustomerID == CustomerID
                    select t).ToList();

我明白了

无效的对象名称“dbo.TransactionStatus”。

我什至做了一个更简单的测试:

List<TransactionStatus> statuses = db.TransactionStatuses.ToList();

= 结果相同。

我已经从 db 更新(甚至重新创建)edmx 并反复检查它,试图找出 dbo.TransactionStatus* es * 的映射有什么不同,这会使整个事情出错。

如果有人能指出我的修复方向,那就太好了。

PS关闭复数不是一种选择,谢谢。

更新:我想通了-我的回答如下。

4

4 回答 4

32

这可能会发生,因为即使打算使用 Database First 流程,实际上应用程序正在使用 Code First 进行映射。让我再解释一下,因为这可能会造成混淆。:-)

将 Database First 与 EF 设计器和 Visual Studio 中的 DbContext 模板一起使用时,会发生三件非常重要的事情。首先,新的实体数据模型向导会向您的应用程序添加一个连接字符串,其中包含数据库优先模型(即 EDMX)的详细信息,以便在运行应用程序时可以找到该模型。连接字符串将如下所示:

<connectionStrings>
    <add name="MyEntities"
    connectionString="metadata=res://*/MyModel.csdl|res://*/MyModel.ssdl|res://*/MyModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\sqlexpress;initial catalog=MyEntities;integrated security=True;multipleactiveresultsets=True;App=EntityFramework&quot;"
    providerName="System.Data.EntityClient" />
</connectionStrings>

其次,生成的上下文类调用指定此连接字符串名称的基本 DbContext 构造函数:

public MyEntities()
: base("name=MyEntities")
{
}

这告诉 DbContext 在配置中查找并使用“MyEntities”连接字符串。使用 "name=" 意味着如果 DbContext 找不到连接字符串,它将抛出 - 它不会继续按照约定创建连接。

如果要使用 Database First,则必须使用生成的连接字符串。具体来说,它必须包含模型数据(来自 EDMX 的 csdl、msl、ssdl),并且您必须确保 DbContext 找到它。更改对基本构造函数的调用时要非常小心。

发生的第三件事是 OnModelCreating 在生成的上下文中被覆盖并抛出:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    throw new UnintentionalCodeFirstException();
}

这样做是因为 OnModelCreating 仅在使用 Code First 时才被调用。这是因为 OnModelCreating 是关于创建模型的,但是当您使用 Database First 时,模型已经存在——在运行时不需要创建任何东西。因此,如果调用 OnModelCreating 则可能是因为您开始使用 Code First 时没有任何意义,通常是因为更改了连接字符串或调用了基本构造函数。

现在,您可能希望使用 Code First 映射到现有数据库。这是一个很棒的模式并且完全受支持(参见http://blogs.msdn.com/b/adonet/archive/2011/03/07/when-is-code-first-not-code-first.aspx)但是你需要确保正确设置映射才能使其正常工作。如果映射设置不正确,那么您将遇到此问题中的异常。

于 2012-02-26T22:00:34.013 回答
7

知道了!可怕的,可怕的经历......

简而言之:EF 无法正确复数以“s”结尾的实体名称(例如“status”、“campus”等)

这是我得到它和证明的方法。

  • 我已经多次创建并重新创建了我的原始设置,结果相同。
  • 我还尝试将我的表重命名为之类TransStatus的东西 - 不走运。
  • 当我对此进行研究时,我偶然发现了 Scott Hanselman 的复数化文章sheep,他在文章中为and之类的词添加了复数化规则goose。这让我想到“如果他的问题出在实体的实际名称上怎么办?
  • status特别搜索了这个词,并在 Connect 上找到了这个问题的报告。我急于尝试重命名我的实体...
  • 重命名TransactionStatusesTransactionStates(同时将列保持为StatusID解决了这个问题!我现在可以得到List<TransactionState> statuses = db.TransactionStates.ToList();
  • 我以为问题出status在名称中的特定单词上……但是在向朋友大声抱怨后,有人建议我可能问题出在以“s”结尾的单词上……所以我决定检查一下.
  • 我设置了另一个名为Campuses并匹配 POCO的表Campus(并更新了 edmx)。做了简单的测试List<Campus> test = db.Campuses.ToList();,得到了现在的预期

无效的对象名称“dbo.Campus”。

所以你去吧,强大的 EF 无法处理以“s”结尾的单词的复数形式。希望下一个遇到问题的可怜虫能找到这个问题,并为他或她自己节省 3-4 小时的痛苦和沮丧。

于 2012-02-25T22:58:37.283 回答
0

你提到了 EDMX,但我不知道你是先用 EDMX 做数据库还是先用代码做数据库,然后只用 EDMX 看看发生了什么。

如果您使用 Code First,那么您可以使用配置来指定表名。Data Annotation 是 [Table("TransactionStatuses")],fluent 是 modelBuilder.Entity().ToTable("TransactionStatuses")。(我正在从内存中输入注释和流畅的代码,因此请仔细检查参考。;))

如果您首先使用数据库,那么 SSDL 绝对应该知道数据库表的名称,所以我猜您首先使用的是代码,而 edmx 只是为了探索。(???)

hth

于 2012-02-25T14:31:04.383 回答
0

叹。类别和模型的照片和视频存在相同类型的问题;它正在寻找照片和视频表。我讨厌只更改表名,但看起来并没有太多选择。

于 2013-12-15T01:18:01.213 回答