1

I'm having a problem updating an object in EF Core 7. On an update (during the SaveChanges method), I get the following error:

Cannot insert the value NULL into column 'QueryName', table 'Lightwave360.dbo.Query'; column does not allow nulls. UPDATE fails

The object in question, Query, has a one-to-many relationship with another object, QueryParameter. The error message says the QueryName property is null. However, I'm 100% sure it is not null prior to the update.

Everything works correctly when I do a create/insert instead of an update. The update is the only thing that fails.

I'm hoping someone out there has had a similar issue. I've been trying to figure this out for a couple of days, but nothing has helped.

Here is the full error message:

SqlException: Cannot insert the value NULL into column 'QueryName', table 'Lightwave360.dbo.Query'; column does not allow nulls. UPDATE fails.

Here is my code - table definitions:

CREATE TABLE [Query]
(
    [QueryId] [int] IDENTITY(1,1) NOT NULL,
    [QueryName] [varchar](100) NOT NULL,
    [Sql] [ntext] NOT NULL,
    [ConnectionId] [int] NOT NULL,
    [Active] [bit] NOT NULL,
    [FolderId] [int] NOT NULL,
    [LastModifiedUser] [varchar](50) NULL,
    [LastModifiedDate] [datetime] NULL,

    CONSTRAINT [PK_Query] 
        PRIMARY KEY CLUSTERED ([QueryId] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

CREATE TABLE [QueryParameter]
(
    [QueryParameterId] [int] IDENTITY(1,1) NOT NULL,
    [QueryId] [int] NOT NULL,
    [ParameterName] [varchar](25) NOT NULL,
    [ParameterType] [smallint] NOT NULL,
    [DataType] [smallint] NOT NULL,
    [Label] [varchar](50) NOT NULL,
    [DynamicParameterId] [int] NULL,
    [Required] [bit] NOT NULL,
    [DefaultValue] [varchar](254) NULL,
    [DisplayOrder] [smallint] NOT NULL,

    CONSTRAINT [PK_QueryParameter] 
        PRIMARY KEY CLUSTERED ([QueryParameterId] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE UNIQUE NONCLUSTERED INDEX [IX_Query] 
ON [Query] ([QueryName] ASC)
       WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
             SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, 
             DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

ALTER TABLE [QueryParameter] CHECK CONSTRAINT [FK_QueryParameter_Query]

Here are the class definitions:

[Table(nameof(Query))]
public partial class Query
{
    public Query() 
    { 
        QueryParameters = new List<QueryParameter>();
    }

    [Key]
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int QueryId { get; set; }

    [Required]
    public string QueryName { get; set; }

    [Required]
    public string Sql { get; set; }

    [Required]
    public int ConnectionId { get; set; }

    public bool Active { get; set; } = true;

    [Required]
    public int FolderId { get; set; }

    public string? LastModifiedUser { get; set; }

    public DateTime? LastModifiedDate { get; set; }
    [ForeignKey(nameof(ConnectionId))]
    public virtual Connection Connection { get; set; }
    [ForeignKey(nameof(FolderId))]
    public virtual Folder Folder { get; set; }
    
    public ICollection<QueryParameter>? QueryParameters { get; set; }
}

[Table("QueryParameter", Schema = "dbo")]
public partial class QueryParameter
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int QueryParameterId { get; set; }

    [Required]
    public int QueryId { get; set; }

    [Required]
    public string ParameterName { get; set; }

    [Required]
    public QueryParameterType ParameterType { get; set; }

    [Required]
    public QueryParameterDataType DataType { get; set; }

    [Required]
    public string Label { get; set; }

    public int? DynamicParameterId { get; set; }

    public bool Required { get; set; }

    public string DefaultValue { get; set; }

    public short DisplayOrder { get; set; }

    [ForeignKey(nameof(DynamicParameterId))]
    public DynamicParameter DynamicParameter { get; set; }

    [ForeignKey(nameof(QueryId))]
    public Query Query { get; set; }
}

Here is the update code:

public IActionResult PutQuery(int key, [FromBody] Lightwave.Data.Query item)
{
        try
        {
            ModelState.Clear();
            //if(!ModelState.IsValid)
            //{
            //    return BadRequest(ModelState);
            //}

            if(item == null || (item.QueryId != key))
            {
                return BadRequest();
            }

            item.LastModifiedDate = DateTime.Now;
            OnQueryUpdated(item);

            _context.Queries.Update(item);
            _context.SaveChanges();

            var itemToReturn = _context.Queries
                .Include(i => i.Connection)
                .Include(i => i.Folder)
                .Include(i => i.QueryParameters)
                .Where(i => i.QueryId == key);
            Request.QueryString = Request.QueryString.Add("$expand", "Connection");
            OnAfterQueryUpdated(item);

            return new ObjectResult(SingleResult.Create(itemToReturn));
        }
        catch(Exception ex)
        {
            ModelState.AddModelError("", ex.GetBaseException().Message);
            _logger.LogError(ex.GetBaseException(), ex.GetBaseException().Message);
            return BadRequest(ModelState);
        }
}

If anyone has any suggestions, I would greatly appreciate it. As I've said, I've been working on this for a couple of days and have exhausted all efforts that I can think of.

Thanks.

UPDATE: I'm still trying to figure this thing out. I wanted to add the SQL that is being generated on the backend during the Update/SaveChanges(). It looks as though it is deleting the entity, then inserting it back. Again, if anyone can help out, it would be greatly appreciated. Here is the generated SQL:

exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Query]
OUTPUT 1
WHERE [QueryId] = @p0;
MERGE [Query] USING (
VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7, 0),
(@p8, @p9, @p10, @p11, @p12, @p13, @p14, 1)) AS i ([Active], [ConnectionId], [FolderId], [LastModifiedDate], [LastModifiedUser], [QueryName], [Sql], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Active], [ConnectionId], [FolderId], [LastModifiedDate], [LastModifiedUser], [QueryName], [Sql])
VALUES (i.[Active], i.[ConnectionId], i.[FolderId], i.[LastModifiedDate], i.[LastModifiedUser], i.[QueryName], i.[Sql])
OUTPUT INSERTED.[QueryId], i._Position;
',N'@p0 int,@p1 bit,@p2 int,@p3 int,@p4 datetime2(7),@p5 nvarchar(4000),@p6 nvarchar(4000),@p7 nvarchar(4000),@p8 bit,@p9 int,@p10 int,@p11 datetime2(7),@p12 nvarchar(4000),@p13 nvarchar(4000),@p14 nvarchar(4000)',@p0=10,@p1=1,@p2=1,@p3=0,@p4=NULL,@p5=NULL,@p6=NULL,@p7=NULL,@p8=1,@p9=0,@p10=1,@p11=NULL,@p12=NULL,@p13=NULL,@p14=NULL
7
  • 1
    Where in the code shown are you performing the update operation? Commented Apr 21, 2023 at 17:15
  • Set not null value for Query.QueryName. Other than that you can add a minimal reproducible example showing how do you try to fill and save the data Commented Apr 21, 2023 at 17:16
  • How about manually setting the value of QueryName to item. QueryName = "Test Value"; Commented Apr 21, 2023 at 18:09
  • I've tried that. When I profile the SQL generated it looks like all data is set to null when executing on the SQL Server. Commented Apr 21, 2023 at 18:11
  • What does your OnQueryUpdated and OnAfterQueryUpdated methods look like? You should do a _context.Queries.Find(item.QueryId) call, then update the values you wish to update. Commented Apr 21, 2023 at 18:19

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.