1

What is the best way to prevent a property from changing after it was added to the database?

I know I can do it by tracking state when I am actually using the DbContext in the application. But then it's up to the programmer.

I would like this to be included in a DbContext override or inside the model configuration. Then it would work automatically and reject the change when someone tries to update the property.

One way to solve it would be by overriding ValidateEntity and check it there, but I am wondering if this is the best solution

2 Answers 2

1

Implement the property in your entity class with your own backing variable (old school) and a flag denoting whether or not the property has already been set once:

    private DateTime _created;
    private bool _createdSet = false;

    public DateTime Created 
    {
        get
        {
            return _created;
        }
        set
        {
            if (_createdSet)
            {
                throw new InvalidOperationException("Property 'Created' cannot be changed once set");
            }

            _createdSet = true;
            _created = value;
        }
    }
Sign up to request clarification or add additional context in comments.

1 Comment

this solution seems to be the simplest.
1

You can put it in the model by making the property setter private. As far as I know EF maps private properties as well. Or you can create a public property (ignored in map) based on a private property (mapped) and put the logic there. If the model is not in your hand then it should be in the context as you mentioned. ValidateEntity sounds to be a right place but honestly I have no experience doing such thing.

EDIT: I tryied the following

public class Entity
{
    public int Id { get; set; }
    public string Code { get; private set; }

    public string MyCode 
    { 
        get { return this.Code; }
        set
        {
            if (string.IsNullOrEmpty(this.Code))
            {
                this.Code = value;
            }
        }
    }
}

And in the context OnModelCreating

modelBuilder.Entity<Entity>()
    .ToTable("dbo.Entity")
    .HasKey(s => s.Id);

modelBuilder.Entity<Entity>()
    .Property(s => s.Code)
    .IsRequired();

modelBuilder.Entity<Entity>()
    .Ignore(s => s.MyCode);

And it works.

6 Comments

but EF can't set the property on load from the DB, so this doesn't work
Thanks! I guess I could make the setter private and then have a seperate factory method to create the entity that takes the set-once property value as a parameter allowing to update the private field
From Julie Lerman's book: Entity Framework will use reflection to access a nonpublic setter, this means that the context will be able to populate restricted properties when materializing objects as a result of a query or an insert. So this seems to handle it. I will give it a try
Yes, that's correct EF uses reflection just as DataContractSerializer can instantiate objects without calling the constructor, or set private properties. Furthermore, I think they use an internal version of reflection with even more privileges.
I still prefer my solution, however, as it informs the 'user' of an invalid operation. This solution hides the fact that the user can't change the value.
|

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.