Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InMemory provider in EF Core 6 doesn't set value for Timestamp-fields #26686

Closed
cwe1ss opened this issue Nov 15, 2021 · 6 comments
Closed

InMemory provider in EF Core 6 doesn't set value for Timestamp-fields #26686

cwe1ss opened this issue Nov 15, 2021 · 6 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@cwe1ss
Copy link

cwe1ss commented Nov 15, 2021

Congratulations on the 6.0 release! 👍

I've been trying to upgrade our solution from EF Core 5 to EF Core 6 and we now get the following exception in our unit tests where we use the InMemory provider (instead of the SQL provider):

  Message: 
    Microsoft.EntityFrameworkCore.DbUpdateException : Required properties '{'ETag'}' are missing for the instance of entity type 'MyEntity' with the key value '{Id: a4b1d638-27f6-4129-ae48-4fed1fc28584}'.

  Stack Trace: 
    InMemoryTable`1.ThrowNullabilityErrorException(IUpdateEntry entry, IList`1 nullabilityErrors)
    InMemoryTable`1.Create(IUpdateEntry entry)
    InMemoryStore.ExecuteTransaction(IList`1 entries, IDiagnosticsLogger`1 updateLogger)
    InMemoryDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
    StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
    StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
    DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
    DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)

The ETag property is defined like this:

[Required, Timestamp]
public byte[] ETag { get; protected set; }

I've seen that the InMemory provider now enforces required fields but as this value has always been set automatically by the SQL provider, I'm wondering how to handle this now.

Is this a bug and should the InMemory-provider initalize this property automatically for me in the same way as the SQL provider?

Should I set this property myself? If so, which value should I use?

Include provider and version information

EF Core version: 6.0.0
Database provider: InMemory
Target framework: .NET 6.0
Operating system: Win 11
IDE: (e.g. Visual Studio 2019 16.3)

Thank you for your help!

@cwe1ss
Copy link
Author

cwe1ss commented Nov 15, 2021

Small addition: I've seen that the Concurrency Tokens-documentation does not use the Required attribute for these properties:
image

If I remove the Required-attribute from my property as well, the unit tests will succeed. However, adding a migration would now want to make the field nullable - and I don't want that.

@cwe1ss
Copy link
Author

cwe1ss commented Nov 15, 2021

Sorry for talking to myself here. 😄 I've done some further digging and found an existing issue that describes that InMemory currently doesn't support Timestamp/Rowversion:

So IIUC, in EF Core 5, InMemory never set any value for it either and our unit tests just worked because we don't currently assert the timestamp-property. This no longer works in EF Core 6 because of the new required-checks.

I understand this behavior and upvoted #10625 - maybe you'll consider adding support for this sometime in the future.

Ideally we'd use SQL for unit testing as well, but that's not an easy task. So if possible, I'd like to stick with InMemory for now and mimic the old behavior in EF Core 6.

An easy fix seems to be to just initialize the property with Array.Empty<byte>() as below. In my quick testing, this resulted in the correct behavior for SQL Server (EF just overwrites it with the actual DB value on save) and InMemory was happy with it not being null as well.

[Required, Timestamp]
public byte[] ETag { get; protected set; } = Array.Empty<byte>();

Do you see any issues with doing this?

@ajcvickers
Copy link
Member

@cwe1ss Seems like a reasonable approach. Alternately, if you're using the in-memory provider in this way and were happy with it not validating required properties, when you could just turn off that validation and continue as before.

@cwe1ss
Copy link
Author

cwe1ss commented Nov 16, 2021

Thank you very much for your response, it's much appreciated! I'll proceed with setting it to Array.Empty<byte>().

@albinsunnanbo
Copy link

The Array.Empty() fix is simple once you find this thread, but it would be really nice if the [Timestamp] attribute suppressed the required check in the InMemory database.

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
@PromidataAchim
Copy link

I have exactly this problem now because mocking for testing is not possible for relational data.
then I read here this is closed as not planned. Why?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

4 participants