1

I would like to ask how to update row that previously was stored as some specific type and should be updated to another specific type.

Let's assume I have configured Entity Framework to use Table Per Hierarchy inheritance strategy. Now, let's say I have these classes:

abstract class Package
{
   public string SomeSharedValue { get; private set; }
}

class PublicPackage : Package 
{
   public int SomeProperty1 { get; private set; }
   public Package TurnIntoPrivatePackage(int someProperty2)
   {
     return new PrivatePackage(someProperty2);
   }
}

class PrivatePackage : Package
{
   public int SomeProperty2 { get; private set; }
   public Package TurnIntoPublicPackage(int SomeProperty1)
   {
     return new PublicPackage(SomeProperty1);
   }
}

and I have configured my model in such a way:

modelBuilder.Entity<Package>(m =>
{
    m.HasDiscriminator<int>("Type")
     .HasValue<PublicPackage>(1)
     .HasValue<PrivatePackage>(2);
});

so right now, how do I turn (update) let's say PublicPackage into PrivatePackage

Would it work if I do something like:

public async Task DoSomething(DbContext dbContext, Guid packageId){
   var package = dbContext.Packages.SingleOrDefaultAsync(f => f.Id == packageId);
   //now package is of type PublicPackage
   var updatedPackage = package.TurnIntoPrivatePackage(someValue)
   //updated package has the same Id and other values setted for private package right now but it's new (another) instance with the same id.
   dbContext.Update(updatedPackage); // Can I do this? should I detach the previous instance?
   await dbContext.SaveChangesAsync()
}
12
  • I'm not sure what you're doing here without more code. But it sounds like you're implementing inheritance for code reuse. In this case, it makes more sense to use interfaces. That way you can have the same object and expose what you need without "turning an instance" into another subclass instance. Commented Dec 1, 2020 at 21:09
  • @PaulCarlton I have an entity called Package. The package may exists as a PrivatePackage or PublicPackage. Both shares some fields from Package but also both have specific fields that make sense only for that kind of type of package. User can dynamically make the package public or private. That's why I have turn some subclass into another. Commented Dec 1, 2020 at 21:17
  • This looks like a classical case of using interfaces. Are you using interfaces to define the contracts of your public/private package? Commented Dec 1, 2020 at 21:33
  • Also, if you don't mind, I'd like to take a look at your Package/Private/Public implementation (you don't need to share the ef model migration code). Commented Dec 1, 2020 at 21:35
  • I will update my post however I think you misunderstood what I'm trying to achieve. What I'm asking is in fact how to update the underlying database row as I'm not sure if entity framework will handle that for me if I just call dbContext.UpdateAsync(modifiedPackage) Commented Dec 1, 2020 at 21:39

1 Answer 1

1

Ok, I've got enough of an idea now what you're trying to accomplish.

Problem

You'd like to use table per hierarchy to abstract 2 different types of packages using EF, and you want to know how to change from one package type to another, or in database terms, set the discriminator value to the new value and update the object accordingly.

Solution

You can't directly or explicitly set the discriminator to another value. The github issue here will explain further: https://github.com/dotnet/efcore/issues/7510

In the issue above you can go with their example to work around that to set the discriminator explicitly by setting it meta data property in the model builder. But direct transmutation from one object to another is not supported. Doesn't appear like they'll ever support it.

You'd have to add the following code:

modelBuilder.Entity<Package>()
    //EF Core version 2.0.0 syntax
    .Property("Type").Metadata.AfterSaveBehavior = PropertySaveBehavior.Save

I'm not sure if I'd go this route though unless I was dealing with data that I new was going to be static as far as its types. This problem would make me rethink the approach in this use case.

Sign up to request clarification or add additional context in comments.

Comments

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.