Почему Entity Framework пытается вставить NULL? - PullRequest
10 голосов
/ 16 февраля 2010

У меня есть две таблицы: Цитата и Агент. В кавычке есть столбец с именем 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?

EDIT: Я использую шаблон репозитория в своем приложении. Я использую 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, и он выглядит странно для меня:

insert [dbo]. [Quote] ([QuoteKey], [CommisionAmount], [QuoteRequestID], [DiscoveryMethod], [SelectedOption], [CreatedDateTimeStamp], [SentDateTimeStamp], [CompletedDateTimeStamp], [CustomerName], [CustomerName] ], [CustomerPrimaryPhone], [CustomerAlternatePhone]) значения (@ 0, ноль, ноль, @ 1, ноль, @ 2, ноль, ноль, @ 3, @ 4, @ 5, @ 6) выберите [QuoteID], [AgentID] от [dbo]. [Цитата] где @@ ROWCOUNT> 0 и [QuoteID] = scope_identity ()

Ответы [ 2 ]

6 голосов
/ 05 марта 2010

Я решил свою проблему.

Позвольте мне в предисловии сказать, что я использую ASP.NET MVC - если вы пишете однопользовательское настольное приложение, ваша проблема может полностью отличаться от моей.

В моем случае я, по-видимому, придумал плохое решение проблемы, с которой столкнулся ранее.

Я создавал несколько экземпляров моего объекта-контекста - и когда вы создаете сущности с одним экземпляром и пытаетесь связать их с сущностью, созданной другим экземпляром, вы получаете странные ошибки.

Чтобы обойти это, я подумал, ну, я просто позабочусь, чтобы у меня был только один объект-контекст. Поэтому я создал класс с открытым геттером, который будет создавать экземпляр, если он еще не создан, и возвращать его. Тип одноэлементного шаблона, гарантирующий, что у меня был один объект-контекст для всего приложения.

В моем приложении я время от времени создаю «одноразовые» объекты - например, временная сущность, иногда предварительно заполненная несколькими значениями по умолчанию, просто чтобы я мог визуализировать форму. Когда форма отправлена, новый объект создается, заполняется, проверяется и затем сохраняется.

Сохранение завершится неудачно, но с ошибкой, описанной на этой странице, из-за того, что какой-то атрибут пуст, хотя я заполнил все поля и объект прошел проверку.

Проблема заключалась в том, что он не пытался сохранить объект, который я только что создал - он висел на «выбрасываемом» объекте из предыдущего запроса и пытался сначала сохранить его.

Исходя из PHP, меня поразило осознание того, что приложения ASP.NET MVC имеют жизненный цикл, очень отличный от приложений PHP. В PHP сценарии запускаются, обрабатывают запрос, заканчиваются, а затем заканчиваются - тогда как в ASP.NET они запускаются, работают некоторое время, обслуживая много запросов, а затем, в конце концов, заканчиваются и перезапускаются.

Создавая мой объект-контекст в статическом методе, я создавал не один экземпляр для запроса, а один экземпляр для приложения. Поскольку объект-контекст сохраняется между запросами, мои «одноразовые» сущности накапливаются - и, в конце концов, когда я пытаюсь сохранить SaveChanges (), он, конечно, завершится неудачей.

Эта путаница частично проистекает из того факта, что Entity Framework был написан с учетом настольных приложений - он не был разработан для жизненного цикла веб-приложения.

Вы можете обойти это, и вот решение:

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

Надеюсь, что это полезно для других: -)

0 голосов
/ 16 февраля 2010

Вы проверяете значение entity.Agent? Я подозреваю, что значение null исходит от FirstOrDefault(), когда он встречает запрос, который не возвращает записей.

Даже если для объекта агента установлены все его значения, это не имеет значения, если entity не имеет ссылки на объект агента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...