2009-08-25 4 views
4

Я испытываю очень неприятную проблему при попытке вставить новую запись с использованием LINQ to SQL. Если я прохожу через этот код, он иногда вставляет новую запись , но большую часть времени ее нет. Когда он не работает, я вижу следующую ошибку.LINQ to SQL INSERT Failed

Не удается вставить значение NULL в столбце 'Name', таблица 'EquipmentManufacturer'; колонка не разрешать nulls. INSERT терпит неудачу. Заявление прекращено.

Эта ошибка возникает из-за поля "Имя", которое недействительно. Когда я отлаживаю и просматриваю эту коллекцию, [«Имя»] имеет значение, введенное в форму.

Вот инструкция создания таблицы.

CREATE TABLE [EquipmentManufacturer] (
    [EquipmentManufacturerID] [int] IDENTITY(1,1) NOT NULL, 
    [Name] [nvarchar](50) NOT NULL, 

CONSTRAINT [PK_EquipmentManufacturer] PRIMARY KEY CLUSTERED 
(
    [EquipmentManufacturerID] ASC 
) ON [PRIMARY] 
) ON [PRIMARY] 

Вот ASP.NET MVC Controller и Create Action, где я пытаюсь добавить новую запись.

public partial class EquipmentManufacturerController : Controller 
{ 
    private IRepository<EquipmentManufacturer> reposManu; 

    // POST: /EquipmentManufacturer/Create 
    [AcceptVerbs(HttpVerbs.Post)] 
    public virtual ActionResult Create(FormCollection collection) 
    { 
    EquipmentManufacturer entity = reposManu.New(); 
    try 
    { 
     //HACK: Something screwy is going on here the entity oject doesn't always get updated correctly 
     //UpdateModel(entity); 

     entity.Name = collection["Name"]; 
     reposManu.Insert(entity); 
     reposManu.SubmitChanges(); 

     return RedirectToAction("Details", new { id = entity.EquipmentManufacturerID }); 
    } 
    catch (RulesException ex) 
    { 
     ex.AddModelStateErrors(ModelState, "EquipmentManufacturer"); 
     return ModelState.IsValid ? RedirectToAction("Create") 
     : (ActionResult)View(); 
    } 
    } 
} 

Вот вид Create.aspx.

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 

    <h2>Create</h2> 

    <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %> 

    <% using (Html.BeginForm()) {%> 

     <fieldset> 
      <legend>Fields</legend> 
      <p> 
       <label for="Name">Name:</label> 
       <%= Html.TextBox("Name") %> 
       <%= Html.ValidationMessage("Name") %> 
      </p> 
      <p> 
       <input type="submit" value="Create" /> 
      </p> 
     </fieldset> 

    <% } %> 
    <%= Html.ClientSideValidation<EquipmentManufacturer>() %> 

    <div> 
     <%=Html.ActionLink("Back to List", "Index") %> 
    </div> 

</asp:Content> 

Реализация хранилища, которую я использую.

public class Repository<T> : IRepository<T> where T : class 
{ 
    public IDataContext DC { get; set; } 

    public Repository(IDataContext dataContext) 
    { 
     DC = dataContext; 
    } 

    /// <summary> 
    /// Return all instances of type T. 
    /// </summary> 
    /// <returns></returns> 
    public IEnumerable<T> All() 
    { 
     return GetTable; 
    } 

    /// <summary> 
    /// Return all instances of type T that match the expression exp. 
    /// </summary> 
    /// <param name="exp"></param> 
    /// <returns></returns> 
    public IQueryable<T> Find(Expression<Func<T, bool>> exp) 
    { 
     return GetTable.Where<T>(exp); 
    } 

    /// <summary>See IRepository</summary> 
    /// <param name="exp"></param> 
    /// <returns></returns> 
    public T Single(Expression<Func<T, bool>> exp) 
    { 
     return GetTable.SingleOrDefault(exp); 
    } 

    /// <summary>See IRepository</summary> 
    /// <param name="exp"></param> 
    /// <returns></returns> 
    public T First(Expression<Func<T, bool>> exp) 
    { 
     return GetTable.First(exp); 
    } 

    /// <summary>See IRepository</summary> 
    /// <param name="entity"></param> 
    public virtual void Delete(T entity) 
    { 
     DC.Context.GetTable<T>().DeleteOnSubmit(entity); 
    } 

    /// <summary> 
    /// Create a new instance of type T. 
    /// </summary> 
    /// <returns></returns> 
    public virtual T New() 
    { 
     T entity = Activator.CreateInstance<T>(); 
     GetTable.InsertOnSubmit(entity); 
     return entity; 
    } 

    /// <summary> 
    /// Adds an insance T. 
    /// </summary> 
    /// <returns></returns> 
    public virtual void Insert(T entity) 
    { 
     GetTable.InsertOnSubmit(entity); 
    } 

    /// <summary> 
    /// Update entity. 
    /// </summary> 
    /// <returns></returns> 
    public virtual void Update(T entity) 
    { 
     DC.Context.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, entity); 
    } 

    /// <summary>See IRepository</summary> 
    public void SubmitChanges() 
    { 
     DC.SubmitChanges(); 
    } 

    private string PrimaryKeyName 
    { 
     get { return TableMetadata.RowType.IdentityMembers[0].Name; } 
    } 

    private System.Data.Linq.Table<T> GetTable 
    { 
     get { return DC.Context.GetTable<T>(); } 
    } 

    private System.Data.Linq.Mapping.MetaTable TableMetadata 
    { 
     get { return DC.Context.Mapping.GetTable(typeof(T)); } 
    } 

    private System.Data.Linq.Mapping.MetaType ClassMetadata 
    { 
     get { return DC.Context.Mapping.GetMetaType(typeof(T)); } 
    } 
} 

ответ

3

Это потому, что вы вызываете .InsertOnSubmit (сущность) дважды?

Вы называете это раз в New()

public virtual T New() 
{ 
    T entity = Activator.CreateInstance<T>(); 
    GetTable.InsertOnSubmit(entity); 
    return entity; 
} 

А потом снова в .Применять()

public virtual void Insert(T entity) 
{ 
    GetTable.InsertOnSubmit(entity); 
} 

Лично я хотел бы удалить GetTable.InsertOnSubmit (лицо) от нового() метод.

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

HTHS,
Чарльз

+0

Это похоже на решение моей проблемы, однако я не совсем понимаю, почему. Если я комментирую GetTable.InsertOnSubmit (сущность) из метода Repository New, он работает. Если я оставлю вызов InsertOnSubmit в методе Repository New и закомментирую вызов reposManu.Insert (entity) в контроллере, он завершится с ошибкой. – MHinton

+0

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

+0

Спасибо, что на самом деле имеет смысл. – MHinton

0

В моем опыте такая проблема обычно возникает из-за ошибок в конфигурации сопоставления.

Некоторые предложения для нахождения ответа:

  • Использование SQL Profiler для отслеживания заявления INSERT, которые могли бы дать вам больше ключей.

  • Двойной контроль соответствия для класса EquipmentManufacturer, имя может быть неправильно отображено. Включите эту информацию в свой вопрос, поскольку она обеспечивает лучшую картину проблемы.

+0

Я использовал SQL Profiler, и я вижу, что переданный параметр Name равен null. Я не знаю, что происходит, потому что на этой строке reposManu.Insert (entity) entity.Name не является нулевым. – MHinton

+0

Проследите, что делает LINQ to SQL, когда он извлекает значение для вставки - очевидно, что сопоставление столбца Name, как и в SQL, но вы проверили, что запись сопоставления (атрибуты или XML) фактически указывает на правильное свойство/поле в классе сущности? – Sam

0

Я вижу, что вы не используете «автоматической привязки» (или как вы ее называете, где принимает объект, который вы хотите прикрепить в качестве параметра метода действия), но вместо того, чтобы (A) newing объект и (B) установить его свойство «Имя» из формыCollection вручную. Возможно, я не вижу, где связывается «EquipmentManufacturerID»?

Является ли NULL-отказ на этом свойстве EquipmentManufacturerID?

+0

Отсутствует его свойство Name. Я попытался использовать подпись метода, например, публичный виртуальный ActionResult Create ([Bind()] EquipmentManufacturer), и у меня все еще есть та же проблема. – MHinton

+0

Вы пытались зарегистрировать базовый SQL, который генерирует LTS? Если бы вы могли видеть, что именно отправляет сервер, это может помочь вам отладить это дальше ...? – Funka

1

Я столкнулся с этой проблемой, потому что я установил опцию Auto Generated Value в моем * DBML-файл Ling2SQL в true; Я изменил его на false, и ошибка исчезла. Его простая ошибка, но мне потребовалось навсегда найти, поскольку я не намеренно установил значение true.