What is the purpose of Entity Framework attempting to insert NULL?

.net entity-framework

Question

I have Quote and Agent tables. A foreign key in Agent's Quote table is named AgentID.

A reference to Agent was found in the Quote class when I added the tables to my model in Visual Studio.

I create a new quote object when trying to add a new quote, and I configure the Agent as follows:

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

I inspect the object just before SaveChanges is called and confirm that all of the values are set. The values of the Agent object are all set. Even the EntityKey attribute, which is set, was tested.

I am seeing the following error despite the values being present:

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

What more should I look into? Is there a method to inspect the SQL, perhaps?

EDIT: In my application, I'm utilizing the repository pattern. In my application, I utilize PONOs before creating new entity objects. The approach I use to store a fresh quotation is called:

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)
        }

Here's a strange thing. I was able to examine the resulting SQL, and it strikes me as odd:

put in [dbo]. Select [QuoteID], [AgentID] from [dbo] with the following parameters: [Quote]([QuoteKey], [CommisionAmount], [QuoteRequestID], [DiscoveryMethod], [SelectedOption], [CreatedDateTimeStamp], [SentDateTimeStamp], [CompletedDateTimeStamp], [CustomerName], [CustomerEmail], [ @@ROWCOUNT > 0 and [QuoteID] = scope identity, [Quote] ()

1
10
2/17/2010 12:29:10 AM

Popular Answer

My issue was resolved.

I'm using ASP.NET MVC, so let me start by mentioning that your issue may not be the same as mine if you're developing a desktop application for a single user.

In my instance, I seemed to have made a poor resolution to a preexisting issue.

I was constructing numerous instances of my object-context, and you get strange problems when you attempt to correlate things generated by one instance with entities made by another instance.

I reasoned that I could get around it by making sure I only had one object-context. So I made a class with a public getter that would return the instance or construct it if it hadn't previously been created. To make sure I had a single object-context for the whole program, I kind of used the singleton design.

I sometimes generate "throw-away" objects in my app only to display a form, like a transient entity that is sometimes pre-populated with a few default values. When the form is submitted, a new object is created, populated, validated, and then saved.

Even though I had filled in every field and the entity had passed validation, the save would still fail and display the error given on this page about some property being empty.

The issue was that it was holding onto the "throw-away" object from the prior request and attempting to save that one first, rather than trying to save the object I had just generated.

The revelation that ASP.NET MVC projects have a completely different lifetime from PHP apps was what confused me since I am a PHP developer. Unlike ASP.NET, where scripts start, run for a long, handle a lot of requests, and then finally stop and restart, PHP scripts begin, process a request, and then terminate.

I was generating one instance per application, not one per request, when I created my object-context in a static function. My "throw-away" entities will accumulate since the object-context survives across requests, and ultimately, when I attempt to SaveChanges(), it will obviously fail.

The Entity Framework was created with desktop programs in mind; it was not planned for the life-cycle of a web application, which contributes to this uncertainty.

This may be overcome, and the remedy is as follows:

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;
        }
    }
}

Your object-context is now accessible from anywhere:

MyEntities DB = MyNamespace.App.DB;

This extensive paper that examines several methods for controlling the lifespan of an object-context led me to the resolution:

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

I hope that this is useful to others:-)

6
3/5/2010 3:13:45 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow