Entity Framework 5: Using DatabaseGeneratedOption.

2019-02-12 16:20发布

问题:

I have an EF5 code first project that uses the [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute. This option is overriding my settings.

Consider this SQL table:

CREATE TABLE Vehicle (
  VehicleId  int identity(1,1) not null,
  Name varchar(100) not null default ('Not Set')
)

I am using the SQL default construct to set the [Name] is case it is not set.

In code behind, I have a class defined similar to:

public class Vehicle {
   ...

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public string ShoulderYN { get; set; }
}

When I update the entity in code, the value set in the default overrides my new setting.

In code, I have (pseudo):

vehicle.Name = 'Update Name of Vehicle';
_dbContext.Update(vehicle);
_dbContext.SaveChanges();

The expected result is Vehicle.Name = 'Update Name of Vehicle'.

The actual result is Vehicle.Name = 'Not Set'.

Is there a way in EF5 to say "if Vehicle.Name is null/empty, use the value defined in the database? Otherwise, if I set the value in code, I want to use this value."

Thanks.

Steve

回答1:

Apparently, no there isn't. It's not that smart :)

As you may already read, Computed option just tells the EF not to update your column, beacause you will compute a value on the DB-side yourself. EF will then just return newly computed value from your database (which in your case is "Not Set").

Your basic three options are - as per EF Source code documentation:

  • None - The database does not generate values.
  • Identity - The database generates a value when a row is inserted.
  • Computed - The database generates a value when a row is inserted or updated.

https://github.com/aspnet/EntityFramework6/blob/527ae18fe23f7649712e9461de0c90ed67c3dca9/src/EntityFramework/DataAnnotations/Schema/DatabaseGeneratedOption.cs

Since you expect a little more custom logic to be done, I'm afraid you would have to do it yourself. I would suggest you stop relying on database default constraint and do everything in code first approach. This way you would have a code like that:

public class Vehicle
{
  public Vehicle()
  {
    this.Name = "Not set";
  }

  // Without 'Generated' attribute
  public string Name { get; set; }
}

This way, when your Entity is created, it automatically starts with expected default value. And can be later changed by simply modifying the Name property.

Hope it helps!



回答2:

I checked this for hours to get good answer but no: EF cannot update models by automatic generated-ID.

You have 3 options:

  1. Adding another VehicleId to Vehicle model.
  2. Change automatic generated-ID to be manual generated by you.
  3. Setting unique identifier to be something else then the generated-ID in your model. In your Vehicle Class it can be the Name property.

I suggest you option 3: Setting up unique-id to be Vehicle.Name (and you can add more properties). Then: if vehicle by unique-id doesn't exists, add new vehicle to db-context:

//if there is no such a Vehicle in system, add it:
if (vehicle.Name !=null && vehicle.Name != String.Empty && _dbContext.Where(v => v.Name == vehicle.Name).FirstOrDefault() == null)
    _dbContext.Add(vehicle);

_dbContext.SaveChanges();


回答3:

Actually there is a simple solution for this:

  • You need to leave default constraint with value in table creation script as it is now:

    CREATE TABLE Vehicle (
      VehicleId  int identity(1,1) not null,
      Name varchar(100) not null default ('Not Set')
    )
    
  • Just remove DatabaseGenerated attribute from property in class definition:

    public class Vehicle {
       ...
    
       [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
       public string ShoulderYN { get; set; }
    }
    

And that's it: now database will use default value only if you do not specify some value in code. Hope this helps.