skip to Main Content

Well, I have the following model structure: I have one class – DatabaseEntity which is basically

public class DatabaseEntity
{
    public int Id { get; set; }
}

so each entity like product, category etc will inherit DatabaseEntity and have Id property. Also I have typical EntityFramework repository class with InsertOrUpdate method:

private readonly DbContext _database;

public void InsertOrUpdate<TObject>(TObject entity) where TObject : DatabaseEntity
{
    if(entity.Id == default(int))
    {
         // New entity
         DbSet<TObject>().Add(entity);
    }
    else
    {
         // Existing entity
         _database.Entry(entity).State = EntityState.Modified;
    }
    _database.SaveChanges();
}

Then I download from eBay via eBay api list of categoies I have to add to database. Basically category is:

public class EbayCategory : DatabaseEntity
{
    // It has Id since it inherits DatabaseEntity
    public string Name { get; set; }      
    // ... some other properties
}

But, the problem is, when I download those categories I download and their Id properties, which, of course, already have values. And when I try to save them to database like:

public void UpdateCategories(IEnumerable<EbayCategory> newCategories)
{
    foreach (var newCategory in newCategories)
    {
        _repository.InsertOrUpdate(newCategory);
    }
}

I face some issues… First of all, entity.Id != default(int) because it has value, so repository tries to update this entity, instead of adding, but it is not in the database or context so it throws the following exception:

System.Data.Entity.Infrastructure.DbUpdateConcurencyException
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."

… because it thinks that someone else deleted entity which I am trying to update. How can I save this InsertOrUpdate logic, since a lot of projects are based on it, and be able to add items (EbayCategories) with primary key (Id) to database and then update/delete them like other entities without discarding EbayCategory.Id value?

2

Answers


  1. To allow you to manually generate Ids you need a class that has a manually generated ID – so it cannot inherit from DatabaseEntity

    public class EbayCategory
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
    
        public string Name { get; set; }      
        // ... some other properties
    }
    

    Now you will need a different InsertOrUpdate to handle entities that have manually generated keys:

    public void InsertOrUpdate(EbayCategory entity)
    {
        if(Find(entity.ID == null)
        {
             // New entity
             DbSet<EbayCategory>().Add(entity);
        }
        else
        {
             // Existing entity
             _database.Entry(entity).State = EntityState.Modified;
        }
        _database.SaveChanges();
    }
    
    Login or Signup to reply.
  2. Colin’s answer above quite correctly shows how to achieve this setting using data annotations.
    But in the presented problem the entity is a subclass so you can’t add the annotation without changing the entity class.

    There is an alternative configuration method: Fluent Configuration. Here’s my example using an EntityTypeConfiguration class:

    public class LookupSchoolsConfiguration : EntityTypeConfiguration<LookupSchools>
        {
            public LookupSchoolsConfiguration()
            {
                Property(l => l.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
            }
        }
    

    You can also add configuration directly to the modelBuilder as per this post: https://stackoverflow.com/a/4999894/486028

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search