dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.79k stars 3.19k forks source link

Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore does not ignore the value when the object is added. #12093

Closed MikeAlhayek closed 2 years ago

MikeAlhayek commented 6 years ago

EntityCore BeforeSaveBehavior is not ignoring the value when PropertySaveBehavior.Ignore is used.

As per the property well-comment

If PropertySaveBehavior.Ignore then any value set will be ignored when it is in the EntityState.Added state.

But instead, I am running into

Cannot insert explicit value for identity column in table 'Orders' when IDENTITY_INSERT is set to OFF.

screenshot_7

Steps to reproduce

I have the following DbContext class

public class DataContext : DbContext
{
    public DbSet<Order> Orders { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        var modelTypes = typeof(DataContext).GetProperties()
                         .Where(x => x.PropertyType.IsGenericType && x.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
                         .Select(x => x.PropertyType.GetGenericArguments().First())
                         .ToList();

        var identityTypes = new List<Type> { typeof(Int16), typeof(Int32), typeof(Int64) };

        foreach (Type modelType in modelTypes)
        {
            // Find the first property that is named "id" with the types defined in identityTypes collection
            var key = modelType.GetProperties()
                               .FirstOrDefault(x => x.Name.Equals("Id", StringComparison.CurrentCultureIgnoreCase) && identityTypes.Contains(x.PropertyType));

            if (key == null)
            {
                continue;
            }

            modelBuilder.Entity(modelType)
                        .Property(key.Name)
                        .UseSqlServerIdentityColumn()
                        .Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore;
        }
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (optionsBuilder.IsConfigured)
        {
            return;
        }

        optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["ConnectionName"]);
    }
}

I am expecting that any property that is called Id and of the type Int16, Int32 or Int64 would me marked Identity also If one set a value to the Id property, yet called the .Add() or .AddRange() method the Id value would be ignored since I am using Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore

Instead, The Sql Server is returning an error

Cannot insert explicit value for identity column in table 'Orders' when IDENTITY_INSERT is set to OFF.

Partial code listings, or multiple fragments of code, will slow down our response or cause us to push the issue back to you to provide code to reproduce the issue.

Console.WriteLine("Hello World!");

Further technical details

EF Core version: (2.1.0-rc1-final) Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Window 7 Pro 64-bit IDE: Visual Studio 2017 15.6.6

ajcvickers commented 6 years ago

@CrestApps This probably doesn't work because it was never intended to be used with store-generated properties. Can you provide some details as to what problem you are trying to solve with the code above?

MikeAlhayek commented 6 years ago

I use tools like AutoMapper to map my properties. If I forget to add a rule to exclude mapping the Id property, I would get the error

If PropertySaveBehavior.Ignore then any value set will be ignored when it is in the EntityState.Added state.

However, since I am setting a property to be Identity, then I want to just ignore any value in the Identity column when it is in the EntityState.Added state.

ajcvickers commented 6 years ago

@CrestApps By default, EF sets up numeric key properties to get generated values, which means if the value of the property is the CLR default, then it won't be included in the insert, but the generated value will be propagated back as part of saving the entity. So when you say you want to "ignore any value" do you mean anything more than just not including it in the insert? Are you attempting to prevent back propagation of the generated value to the entity? Is the code setting the value of Id to something before Adding the entity? How does all this relate to AutoMapper? Specifically, how are you using AutoMapper such that it affects inserts?

MikeAlhayek commented 6 years ago

This could be something I was doing wrong. But for some reason yesterday the PropertySaveBehavior.Ignore was throwing exception and I was expecting it to simple no include the Id property in the insert.

I am still unsure what have changed for the code to work today comparing to why it did not work yesterday. But this should no longer be an issue. If it happen again, I'll try to gather more info to pin-point what could have been the problem.

Thank you for your time