我有两个表,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()
答案 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;
我在这篇冗长的文章中找到了解决方案,该文章探讨了管理对象上下文生命周期的几种(正确与错误)方法:
希望这对其他人有帮助: - )
答案 1 :(得分:0)
您是否在查看entity.Agent
的值?我怀疑当遇到不返回记录的查询时,null来自FirstOrDefault()
。
即使代理对象设置了所有值,如果entity
没有对代理对象的引用也无关紧要。