Home > Back-end >  EF Invalid Object name when saving changes to _context
EF Invalid Object name when saving changes to _context

Time:10-21

I have an WebAPI to consume the Pokemon public API. I've built it using .NET 5.0 and EF 5.0. Everything went fine until i added my logic to consume the API to the controller and tried to save the changes to the context.

When i run _context.SaveChangesAsync() i'm having an error that says:

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

The thing is, everything was created by EF. I have not created any Table. The classes for deserializing json i created using json2csharp and jsonformatter so i could understand how to properly deserialize them.

What am i doing wrong? Everything seems okay with the code, i'm just lost with this database issue. The database is created also, and tables ar there.

PokemonDtoController.cs

{
    [Route("api/[controller]")]
    [ApiController]
    public class PokemonDtoesController : ControllerBase
    {
        private readonly DataContext _context;
        private PokemonDto currPoke = null;

        public PokemonDtoesController(DataContext context)
        {
            _context = context;
        }

        // GET: api/PokemonDtoes
        [HttpGet]
        public async Task<ActionResult<IEnumerable<PokemonDto>>> Get_pokemons()
        {
            int limit = 3;
            string url = $"https://pokeapi.co/api/v2/pokemon/?ffset={limit}&limit={limit}";
            string json = string.Empty;
            using (HttpClient _client = new HttpClient())
            {
                _client.BaseAddress = new Uri(url);
                _client.DefaultRequestHeaders.Accept.Clear();
                _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpResponseMessage response = await _client.GetAsync(url);
                if (response.IsSuccessStatusCode)
                {
                    json = await response.Content.ReadAsStringAsync();
                    BaseResults myDeserializedClass = JsonConvert.DeserializeObject<BaseResults>(json);
                    if (myDeserializedClass != null)
                    {
                        foreach (var result in myDeserializedClass.results)
                        {
                            using (HttpClient insideclient = new HttpClient())
                            {
                                insideclient.BaseAddress = new Uri(result.url);
                                response = await insideclient.GetAsync(result.url);
                                if (response.IsSuccessStatusCode)
                                {
                                    json = await response.Content.ReadAsStringAsync();
                                    //AbilitiesRoot currPokeAbilities = JsonConvert.DeserializeObject<AbilitiesRoot>(json);
                                    currPoke = JsonConvert.DeserializeObject<PokemonDto>(json);
                                    if (currPoke != null)
                                    {
                                        try
                                        {
                                            _context.Add(currPoke);
                                            await _context.SaveChangesAsync();
                                    //        _context.SaveChanges();

                                        }
                                        catch(Exception e)
                                        {
                                            return null;
                                        }
                                        
                                    }

                                }
                            }
                        }
                    }
                }
            }
            return await _context.PokemonDtos.ToListAsync();
        }

DataContext.cs

public class DataContext : DbContext
    {

        protected readonly IConfiguration Configuration;
        public DataContext(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnectionString"));
        }

        public DbSet<PokemonDto> PokemonDtos { get; set; }        

        
    }

Perhaps i should list my steps also. After all code was created, i ran the following commands:

dotnet ef migrations add PokeMigrations3 dotnet ef database update

CodePudding user response:

I believe you need to auto generate the Id property for PokemonDto because the database is not set to automatically generate it.

To make it auto-generate this primary key property, you can use the attribute DatabaseGeneratedAttribute to force the database to auto generate the key:

//using System.ComponentModel.DataAnnotations.Schema;

public class PokemonDto
{
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Guid MyIdProperty { get; set; } // replace with you id property

    // ...
}

An alternative will be to assign the id property before saving changes to DB.

try
{
    currPoke.MyIdProperty = Guid.NewGuid(); // or assign to whatever type it is
    _context.Add(currPoke);
    await _context.SaveChangesAsync();
}

CodePudding user response:

I think there are 2 options.

Option 1:
Id is auto increment but you was inserting manuel with SET IDENTITY_INSERT [TableName] OFF. After that, you forgot execute SET IDENTITY_INSERT [TableName] ON from MSSQL.

Option 2:
You're using Guid for Id field but you dont generate new Guid when it was inserting. You can use someEntity.Id = Guid.NewGuid(); or you can do that with 2 way below.

Way 1:

[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }

Way 2:
You have to identify abstract(is-a)/interface(can-do) entity and other entities must be inheritance this abstracted entity.

override Task<int> SaveChangesAsync(..)/override int SaveChanges(..)
{
    var insertingEntities = ChangeTracker.Entries()
.Where(e => e.Entity is BaseEntity && (e.State == EntityState.Added));
    foreach (var entry in insertingEntities)
    {
        if (entry.Entity is BaseEntity entity)
        {
            if (entry.State == EntityState.Added)
            {
                entity.Id = Guid.NewGuid();
            }
        }
    }        
    return base.SaveChangesAsync(..)/base.SaveChanges();
}
  • Related