Rereading of entity too slow?

Posts   
 
    
PatrickD
User
Posts: 65
Joined: 05-Sep-2006
# Posted on: 10-Apr-2013 17:15:42   

In 4.0 I have got the following issue: In SQL Server I have a table with a default value of GetUtcDate() on a DateTime column. I save a new entity to the database without specifying a value for the property mapped to that column. After the Save(), I immediately read the value of the datetime property and get value 0001-01-01 00:00:00.000.

When I run the same code in the debugger with stepping through the code, the value of the property is correct, the current UTC time.

So it seems that because I step through the code, I give LLBLGen enough time to reread the row.

In 3.5 this code worked fine.

Patrick

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 10-Apr-2013 18:54:12   

adapter, selfservicing? A row isn't read back unless you specify to refetch it. In selfservicing this is triggered by reading a property, so the debugger will trigger this refetch. I don't know what you do to read the value, do you use a property?

There's no 'delay read' btw, everything is on the caller's thread.

COuld you give specific code/steps to reproduce this?

Frans Bouma | Lead developer LLBLGen Pro
PatrickD
User
Posts: 65
Joined: 05-Sep-2006
# Posted on: 10-Apr-2013 20:55:03   

SelfServicing.

Code:


[TestMethod]
public void TEST()
{
  var entity = new EParkerServiceStatusEntity();
  entity.EParkerService = 0;
  entity.Status = 0;
  entity.Save();

  Assert.That(entity.StatusChanged, Is.GreaterThan(DateTime.MinValue));
}

Result of Assert:

Test method IPParking.ParkBase.TestProject.EParkerStatusFixture.TEST threw exception: 
NUnit.Framework.AssertionException:   Expected: greater than 0001-01-01 00:00:00.000
  But was:  0001-01-01 00:00:00.000

The column StatusChanged in the database table has been properly set to the UTC time.

When stepping with the debugger, the Assert succeeds.

Table definition:


CREATE TABLE [dbo].[eParkerServiceStatus](
    [eParkerService] [int] NOT NULL,
    [Status] [int] NOT NULL,
    [StatusChanged] [datetime] NOT NULL,
 CONSTRAINT [PK_eParkerServiceStatus] PRIMARY KEY CLUSTERED 
(
    [eParkerService] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[eParkerServiceStatus] ADD  CONSTRAINT [DF_eParkerServiceStatus_Status]  DEFAULT ((0)) FOR [Status]
GO

ALTER TABLE [dbo].[eParkerServiceStatus] ADD  CONSTRAINT [DF_eParkerServiceStatus_StatusChanged]  DEFAULT (getutcdate()) FOR [StatusChanged]
GO

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 11-Apr-2013 08:23:50   

I reproduced it. And yes, not happened on v3.5. This is my test:

DDL Same as before

RTL ORMSupportClasses: 4.0.13.0406

Reproduce code

[TestMethod]
public void TEST()
{
    var entity = new EParkerServiceStatuEntity();
    entity.EParkerService = 0;
    entity.Status = 0;
    entity.Save();

    var x = entity.StatusChanged;
    Assert.AreNotEqual(x, DateTime.MinValue);
}

Test result

Assert.AreNotEqual failed. Expected any value except:<01/01/0001 12:00:00 a.m.>. Actual:<01/01/0001 12:00:00 a.m.>.

Verbose trace

Method Enter: EntityBase.CheckForRefetch Method Exit: EntityBase.CheckForRefetch: state is not OutOfSync Method Enter: EntityBase.CheckForRefetch Method Exit: EntityBase.CheckForRefetch: already refetching or isdirty. Method Enter: EntityBase.Save(2) Method Enter: DaoBase.PersistQueue Method Enter: DaoBase.AddNew Method Enter: CreateInsertDQ Method Enter: CreateSingleTargetInsertDQ Generated Sql query: Query: INSERT INTO [delay].[dbo].[eParkerServiceStatus] ([eParkerService], [Status]) VALUES (@p1, @p2) Parameter: @p1 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 6. Parameter: @p2 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 0.

Method Exit: CreateSingleTargetInsertDQ Method Exit: CreateInsertDQ Method Enter: DaoBase.ExecuteActionQuery Method Enter: Query.ReflectOutputValuesInRelatedFields Method Exit: Query.ReflectOutputValuesInRelatedFields: no parameter relations. Executed Sql Query: Query: INSERT INTO [delay].[dbo].[eParkerServiceStatus] ([eParkerService], [Status]) VALUES (@p1, @p2) Parameter: @p1 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 6. Parameter: @p2 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 0.

Method Exit: DaoBase.ExecuteActionQuery Method Exit: DaoBase.AddNew Method Exit: DaoBase.PersistQueue Method Enter: DaoBase.PersistQueue Method Exit: DaoBase.PersistQueue Method Exit: EntityBase.Save(2) Method Enter: EntityBase.CheckForRefetch Method Enter: EntityBase.CheckForRefetch Method Exit: EntityBase.CheckForRefetch: already refetching or isdirty. Method Enter: DaoBase.PerformFetchEntityAction Method Enter: CreateSelectDQ Method Enter: CreateSelectDQ Generated Sql query: Query: SELECT [delay].[dbo].[eParkerServiceStatus].[eParkerService] AS [EParkerService], [delay].[dbo].[eParkerServiceStatus].[Status], [delay].[dbo].[eParkerServiceStatus].[StatusChanged] FROM [delay].[dbo].[eParkerServiceStatus] WHERE ( ( [delay].[dbo].[eParkerServiceStatus].[eParkerService] = @p1)) Parameter: @p1 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 6. Method Exit: CreateSelectDQ Method Enter: DaoBase.ExecuteSingleRowRetrievalQuery Executed Sql Query: Query: SELECT [delay].[dbo].[eParkerServiceStatus].[eParkerService] AS [EParkerService], [delay].[dbo].[eParkerServiceStatus].[Status], [delay].[dbo].[eParkerServiceStatus].[StatusChanged] FROM [delay].[dbo].[eParkerServiceStatus] WHERE ( ( [delay].[dbo].[eParkerServiceStatus].[eParkerService] = @p1)) Parameter: @p1 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 6.

Method Exit: DaoBase.ExecuteSingleRowRetrievalQuery Method Exit: DaoBase.PerformFetchEntityAction Method Exit: EntityBase.CheckForRefetch

We will look into it and get back to you.

David Elizondo | LLBLGen Support Team
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 11-Apr-2013 11:27:35   

In adapter it at least works. Looking into why selfservicing doesn't work in this case:


[Test]
public void RefetchWithDefaultInDbTest()
{
    var toInsert = EntityCreator.CreateNewProduct(7); // creates product, no price value set
    toInsert.TestRunId = _testRunID;
    Assert.IsNull(toInsert.Fields.GetCurrentValue((int)ProductFieldIndex.Price));
    using(var adapter = new DataAccessAdapter())
    {
        Assert.IsTrue(adapter.SaveEntity(toInsert, true)); // refetch, pick up default for price.
    }
    Assert.AreEqual(1.0, toInsert.Price);
}
Frans Bouma | Lead developer LLBLGen Pro
PatrickD
User
Posts: 65
Joined: 05-Sep-2006
# Posted on: 11-Apr-2013 11:31:36   

Otis wrote:

In adapter it at least works. Looking into why selfservicing doesn't work in this case:


[Test]
public void RefetchWithDefaultInDbTest()
{
    var toInsert = EntityCreator.CreateNewProduct(7); // creates product, no price value set
    toInsert.TestRunId = _testRunID;
    Assert.IsNull(toInsert.Fields.GetCurrentValue((int)ProductFieldIndex.Price));
    using(var adapter = new DataAccessAdapter())
    {
        Assert.IsTrue(adapter.SaveEntity(toInsert, true)); // refetch, pick up default for price.
    }
    Assert.AreEqual(1.0, toInsert.Price);
}

I don't want to draw wrong conclusions, but it works for SelfServicing when using PK Identity fields which are integers (surrogate keys). I see you are using a decimal, could you also try this with Adapter but then using a datetime column with getutcdate()?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 11-Apr-2013 11:53:00   

PatrickD wrote:

Otis wrote:

In adapter it at least works. Looking into why selfservicing doesn't work in this case:


[Test]
public void RefetchWithDefaultInDbTest()
{
    var toInsert = EntityCreator.CreateNewProduct(7); // creates product, no price value set
    toInsert.TestRunId = _testRunID;
    Assert.IsNull(toInsert.Fields.GetCurrentValue((int)ProductFieldIndex.Price));
    using(var adapter = new DataAccessAdapter())
    {
        Assert.IsTrue(adapter.SaveEntity(toInsert, true)); // refetch, pick up default for price.
    }
    Assert.AreEqual(1.0, toInsert.Price);
}

I don't want to draw wrong conclusions, but it works for SelfServicing when using PK Identity fields which are integers (surrogate keys). I see you are using a decimal, could you also try this with Adapter but then using a datetime column with getutcdate()?

Identity fields are always read back, so that's why you see it works. My test uses a decimal on a nullable column, it never gets a value in the test unless it's set in the DB and actively read back. The query works all right, it sets the values (CurrentValue is set). You'll also see that if you read the property AGAIN it will work.

It's a dumb issue, it fetches the value from the field before the refetch. Of course it then doesn't return the right value. flushed . Working on fix.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 11-Apr-2013 12:08:33   

Fixed. See attached dll.

Attachments
Filename File size Added on Approval
SD.LLBLGen.Pro.ORMSupportClasses.zip 409,266 11-Apr-2013 12:08.41 Approved
Frans Bouma | Lead developer LLBLGen Pro
PatrickD
User
Posts: 65
Joined: 05-Sep-2006
# Posted on: 11-Apr-2013 12:18:54   

Thanks, tested it and works (of course simple_smile )