为什么Entity Framework试图插入NULL?

时间:2010-02-16 19:58:13

标签: .net entity-framework

我有两个表,Quote和Agent。 Quote有一个名为AgentID的列,它是Agent中的外键。

在VS中将表添加到我的模型时,Quote类引用了Agent。

在尝试添加新报价时,我创建了一个新的报价实体,并将代理设置为:

entity.Agent = (from x in entities.AgentEntities 
    where x.AgentID == quote.AgentID select x).FirstOrDefault();

在调用SaveChanges之前,我检查对象并查看是否已设置所有值。 Agent对象的所有值都已设置。我甚至检查了EntityKey属性并设置了它。

尽管存在值,但我收到此错误:

Cannot insert the value NULL into column 'AgentID', table 'Database.dbo.Quote'; 
column does not allow nulls. INSERT fails.

我不确定还有什么要检查的,也许有办法查看SQL?

编辑: 我在我的应用程序中使用存储库模式。我在我的应用程序中使用PONO然后创建新的实体对象。当我保存新报价时,我称之为:

public override void CreateQuote(Quote quoteToCreate)
{
  var entity = ConvertQuoteToQuoteEntity(quoteToCreate);
  entities.AddToQuoteEntities(entity);
  entities.SaveChanges();  //Error is thrown here
}

private QuoteEntity ConvertQuoteToQuoteEntity(Quote quote)
        {
            var entity = new QuoteEntity();

            if (quote != null)
            {
                entity.QuoteID = quote.QuoteID;
                entity.DiscoveryMethod = quote.DiscoveryMethod;
                entity.CompletedDateTimeStamp = quote.CompletedDateTimeStamp;
                entity.CommisionAmount = quote.CommisionAmount;
                entity.QuoteKey = quote.QuoteKey;
                entity.SelectedOption = quote.SelectedOption;
                entity.SentDateTimeStamp = quote.SentDateTimeStamp;
                entity.CustomerName = quote.CustomerName;
                entity.CustomerEmail = quote.CustomerEmail;
                entity.CustomerPrimaryPhone = quote.CustomerPrimaryPhone;
                entity.CustomerAlternatePhone = quote.CustomerAlternatePhone;
                entity.Agent = (from x in entities.AgentEntities where x.AgentID == quote.AgentID select x).First<AgentEntity>();
            }
            return entity;  //Everything looks good here (Agent is fully populated)
        }

这有点奇怪。我能够看到生成的SQL,看起来很奇怪:

插入[dbo]。[Quote]([QuoteKey],[CommisionAmount],[QuoteRequestID],[DiscoveryMethod],[SelectedOption],[CreatedDateTimeStamp],[SentDateTimeStamp],[CompletedDateTimeStamp],[CustomerName],[CustomerEmail ],[CustomerPrimaryPhone],[CustomerAlternatePhone]) 值(@ 0,null,null,@ 1,null,@ 2,null,null,@ 3,@ 4,@ 5,@ 6) 选择[QuoteID],[AgentID] 来自[dbo]。[报价] 其中@@ ROWCOUNT&gt; 0和[QuoteID] = scope_identity()

2 个答案:

答案 0 :(得分:6)

我解决了我的问题。

让我先说我正在使用ASP.NET MVC - 如果您正在编写单用户桌面应用程序,那么您的问题可能与我的完全不同。

在我的情况下,我显然已经找到了解决我之前遇到的问题的糟糕解决方案。

我正在创建我的对象上下文的多个实例 - 当你用一个实例创建实体,并尝试将它们与另一个实例创建的实体相关联时,你会得到奇怪的错误。

为了解决这个问题,我想,好吧,我只是确保我只有一个对象上下文。所以我创建了一个带有公共getter的类,如果尚未创建该实例,则会创建该实例并返回它。一种单例模式,确保我有一个整个应用程序的对象上下文。

在我的应用中,我偶尔会创建“丢弃”对象 - 例如一个临时实体,有时会预先填充一些默认值,这样我就可以渲染一个表单。提交表单后,将创建,填充,验证并保存新对象。

虽然保存会失败 - 给出此页面上描述的错误,关于某些属性为空,即使我填充了所有字段,并且实体已通过验证。

问题是,它没有尝试保存我刚创建的对象 - 它挂在上一个请求中的“丢弃”对象上,并试图先保存该对象。

来自PHP,让我离开的是认识到ASP.NET MVC应用程序与PHP应用程序的生命周期截然不同。在PHP中,脚本启动,处理请求,结束然后结束 - 而在ASP.NET中,它们启动,运行一段时间,提供许多请求,然后最终结束并重新启动。

通过在静态方法中创建我的对象上下文,我每个请求创建的实例不是一个 - 而是每个应用程序创建一个实例。因为对象上下文在请求之间存在,所以我的“丢弃”实体会堆积 - 最终,当我尝试SaveChanges()时,它当然会失败。

这种混淆部分源于实体框架是在考虑桌面应用程序的情况下编写的 - 它不是为Web应用程序的生命周期而设计的。

你可以解决这个问题,这是解决方案:

public class App
{
    public static MyEntities DB
    {
        get {
            // Create (as needed) and return an object context for the current Request:

            string ocKey = "MyEntities_" + HttpContext.Current.GetHashCode().ToString("x");

            if (!HttpContext.Current.Items.Contains(ocKey))
                HttpContext.Current.Items.Add(ocKey, new MyEntities());

            return HttpContext.Current.Items[ocKey] as MyEntities;
        }
    }
}

您现在可以从任何地方获取对象上下文:

MyEntities DB = MyNamespace.App.DB;

我在这篇冗长的文章中找到了解决方案,该文章探讨了管理对象上下文生命周期的几种(正确与错误)方法:

http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx

希望这对其他人有帮助: - )

答案 1 :(得分:0)

您是否在查看entity.Agent的值?我怀疑当遇到不返回记录的查询时,null来自FirstOrDefault()

即使代理对象设置了所有值,如果entity没有对代理对象的引用也无关紧要。