This question already has an answer here:
Entity Framework: Cannot insert explicit value for identity column in table '[table]' when IDENTITY_INSERT is set to OFF
(1 answer)
Closed 8 months ago.
I made a few tables in EF and entered in some seed data where I give value to a few columns with a primary key. When I run the application I am getting the error message:
Cannot insert explicit value for identity column in table 'Persons' when IDENTITY_INSERT is set to OFF.
How do I turn it on? I read on here to use:
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
above the property that is a primary key. I am still getting the same error message unfortunately. Please help.
I added [DatabaseGenerated(DatabaseGeneratedOption.None)] to all my properties that have a primary key. When I ran the migration I can see that the identity column is removed, But I am still getting the same error message.
When I go into SQL SEO I can still see the identity column on my primary key. I tried refreshing the database. What am I doing wrong? The only thing I can do is go into properties and remove the identity, but why can't I do it the way mentioned above?
In EF Core 1.1.2, I got this to work with transactions. In my "database initializer" that put seed data into the tables. I used the technique from this EF6 answer. Here's a sample of the code:
using (var db = new AppDbContext())
using (var transaction = db.Database.BeginTransaction())
{
var user = new User {Id = 123, Name = "Joe"};
db.Users.Add(user);
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT MyDB.Users ON;");
db.SaveChanges();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT MyDB.Users OFF");
transaction.Commit();
}
Had to deal with the same issue and this seems to be a clean solution.
Credit to >> https://github.com/dotnet/efcore/issues/11586
I have made some changes so it now works with .Net Core 3.1 + (Tested in .Net 5) and also added this Method SaveChangesWithIdentityInsert
public static class IdentityHelpers
{
public static Task EnableIdentityInsert<T>(this DbContext context) => SetIdentityInsert<T>(context, enable: true);
public static Task DisableIdentityInsert<T>(this DbContext context) => SetIdentityInsert<T>(context, enable: false);
private static Task SetIdentityInsert<T>(DbContext context, bool enable)
{
var entityType = context.Model.FindEntityType(typeof(T));
var value = enable ? "ON" : "OFF";
return context.Database.ExecuteSqlRawAsync(
$"SET IDENTITY_INSERT {entityType.GetSchema()}.{entityType.GetTableName()} {value}");
}
public static void SaveChangesWithIdentityInsert<T>(this DbContext context)
{
using var transaction = context.Database.BeginTransaction();
context.EnableIdentityInsert<T>();
context.SaveChanges();
context.DisableIdentityInsert<T>();
transaction.Commit();
}
}
Usage
var data = new MyType{SomeProp= DateTime.Now, Id = 1};
context.MyType.Add(data);
context.SaveChangesWithIdentityInsert<MyType>();
Improved solution based on NinjaCross' answer.
This code is added directly in the database context class and allows to save changes by also specifying that identity insert is needed for a certain type (mapped to a table).
Currently, I have only used this for integrative testing.
public async Task<int> SaveChangesWithIdentityInsertAsync<TEnt>(CancellationToken token = default)
{
await using var transaction = await Database.BeginTransactionAsync(token);
await SetIdentityInsertAsync<TEnt>(true, token);
int ret = await SaveChangesExAsync(token);
await SetIdentityInsertAsync<TEnt>(false, token);
await transaction.CommitAsync(token);
return ret;
}
private async Task SetIdentityInsertAsync<TEnt>(bool enable, CancellationToken token)
{
var entityType = Model.FindEntityType(typeof(TEnt));
var value = enable ? "ON" : "OFF";
string query = $"SET IDENTITY_INSERT {entityType.GetSchema()}.{entityType.GetTableName()} {value}";
await Database.ExecuteSqlRawAsync(query, token);
}
Steve Nyholm's answer works fine, but I will provide some extra explanation and some generic code with exception handling.
Normally the context takes care of the transaction, but in this case manually taking care of it is required. Why?
Database context will generate a BEGIN TRAN after the SET IDENTITY_INSERT is issued. This will make transaction's inserts to fail since IDENTITY_INSERT seems to affect tables at session/transaction level.
So, everything must be wrapped in a single transaction to work properly.
Here is some useful code to seed at key level (as opposed to table level):
Extensions.cs
[Pure]
public static bool Exists<T>(this DbSet<T> dbSet, params object[] keyValues) where T : class
{
return dbSet.Find(keyValues) != null;
}
public static void AddIfNotExists<T>(this DbSet<T> dbSet, T entity, params object[] keyValues) where T: class
{
if (!dbSet.Exists(keyValues))
dbSet.Add(entity);
}
DbInitializer.cs
(assumes that model class name is the same as table name)
private static void ExecuteWithIdentityInsertRemoval<TModel>(AspCoreTestContext context, Action<AspCoreTestContext> act) where TModel: class
{
using (var transaction = context.Database.BeginTransaction())
{
try
{
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + typeof(TModel).Name + " ON;");
context.SaveChanges();
act(context);
context.SaveChanges();
transaction.Commit();
}
catch(Exception)
{
transaction.Rollback();
throw;
}
finally
{
context.Database.ExecuteSqlCommand($"SET IDENTITY_INSERT " + typeof(TModel).Name + " OFF;");
context.SaveChanges();
}
}
}
public static void Seed(AspCoreTestContext context)
{
ExecuteWithIdentityInsertRemoval<TestModel>(context, ctx =>
{
ctx.TestModel.AddIfNotExists(new TestModel { TestModelId = 1, ModelCode = "Test model #1" }, 1);
ctx.TestModel.AddIfNotExists(new TestModel { TestModelId = 2, ModelCode = "Test model #2" }, 2);
});
}
The solution proposed by #sanm2009 contains some nice ideas.
However the implementation has some imperfections related to the misusage of Task/async/await.
The method SaveChangesWithIdentityInsert does not return Task, nor await for the calls to EnableIdentityInsert and DisableIdentityInsert.
This could lead to undesired side effects.
The following implementations supports both async/await, and non-awaitable paradigms.
#region IDENTITY_INSERT
public static void EnableIdentityInsert<T>(this DbContext context) => SetIdentityInsert<T>(context, true);
public static void DisableIdentityInsert<T>(this DbContext context) => SetIdentityInsert<T>(context, false);
private static void SetIdentityInsert<T>([NotNull] DbContext context, bool enable)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var entityType = context.Model.FindEntityType(typeof(T));
var value = enable ? "ON" : "OFF";
context.Database.ExecuteSqlRaw($"SET IDENTITY_INSERT {entityType.GetSchema()}.{entityType.GetTableName()} {value}");
}
public static void SaveChangesWithIdentityInsert<T>([NotNull] this DbContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
using var transaction = context.Database.BeginTransaction();
context.EnableIdentityInsert<T>();
context.SaveChanges();
context.DisableIdentityInsert<T>();
transaction.Commit();
}
#endregion
#region IDENTITY_INSERT ASYNC
public static async Task EnableIdentityInsertAsync<T>(this DbContext context) => await SetIdentityInsertAsync<T>(context, true);
public static async Task DisableIdentityInsertAsync<T>(this DbContext context) => await SetIdentityInsertAsync<T>(context, false);
private static async Task SetIdentityInsertAsync<T>([NotNull] DbContext context, bool enable)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var entityType = context.Model.FindEntityType(typeof(T));
var value = enable ? "ON" : "OFF";
await context.Database.ExecuteSqlRawAsync($"SET IDENTITY_INSERT {entityType.GetSchema()}.{entityType.GetTableName()} {value}");
}
public static async Task SaveChangesWithIdentityInsertAsync<T>([NotNull] this DbContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
await using var transaction = await context.Database.BeginTransactionAsync();
await context.EnableIdentityInsertAsync<T>();
await context.SaveChangesAsync();
await context.DisableIdentityInsertAsync<T>();
await transaction.CommitAsync();
}
#endregion
#Steve Nyholm answer is OK, But in .Net core 3 ExecuteSqlCommand is Obsolete, ExecuteSqlInterpolated replacement of ExecuteSqlCommand:
using (var db = new AppDbContext())
using (var transaction = db.Database.BeginTransaction())
{
var user = new User {Id = 123, Name = "Joe"};
db.Users.Add(user);
db.Database.ExecuteSqlInterpolated($"SET IDENTITY_INSERT MyDB.Users ON;");
db.SaveChanges();
db.Database.ExecuteSqlInterpolated($"SET IDENTITY_INSERT MyDB.Users OFF");
transaction.Commit();
}
Another way is to explicitly open a connection then SET IDENTITY_INSERT <table> ON.
var conn = context.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
conn.Open();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Posts ON");
var post = new WeblogPost()
{
Id= oldPost.Pk, // <!--- explicit value to Id field
Title = oldPost.Title,
...
};
context.Posts.Add(post);
conn.Close();
Apparently once a connection has been explicitly opened before an EF request, that connection is not automatically closed by EF, so the setting is applied to the same connection context.
This is the same reason that Steve's response with transactions works as transactions keep a connection alive.
Note: you don't want to put the connection into a using statement if you plan to use the same context again later in the application/request. The connection has to exist, so the best way to clear the connection context is to .Close() it, thereby returning EF to its default behavior of opening and closing the connection per operation.
Below solution worked for me.(Link)
I have added below annotations. and removed [Key] Annotation.
[KeyAttribute()]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
Namespace can be changed according to the entity framework version. For Entity framework core namespace is System.ComponentModel.DataAnnotations.Schema
I did not face a data migration since I have tried in a new project.
Another way is to use ExecuteSqlRaw. Unlike ExecuteSqlInterpolated, you do not have to convert your passed string to a formattable string type.
using (var db = new AppDbContext())
using (var transaction = db.Database.BeginTransaction())
{
var user = new User {Id = 123, Name = "Joe"};
db.Users.Add(user);
db.Database.ExecuteSqlRaw("SET IDENTITY_INSERT MyDB.Users ON");
db.SaveChanges();
db.Database.ExecuteSqlRaw("SET IDENTITY_INSERT MyDB.Users OFF");
transaction.Commit();
}
In order to add related entities with an object graph using the DbContext I used a DbCommandInterceptor which automatically sets INSERT_IDENTITY ON for the table in question and then OFF after the insert. This works with IDs manually set and DbContext.SaveChanges. I used it in my integration tests but after a performance optimization maybe it could be suitable for production code in some cases. Here is my answer to a similar SO question which explains the details.
Use "SET IDENTITY_INSERT [table] ON/OFF" into transaction
public static void TranslateDatabase(ref BDVContext bdvContext)
{
bdvContext.Foro.RemoveRange(bdvContext.Foro);
bdvContext.SaveChanges();
using (var transaction = bdvContext.Database.BeginTransaction())
{
bdvContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT [dbo].[Foro] On");
using (old_balsaContext db = new old_balsaContext())
{
long id = 0;
foreach (ForoA77 post in db.ForoA77.Where(x => x.Fecha > new DateTime(2000,1,1) & x.IdPadre == 0 ) )
{
bdvContext.Foro.Add(new Foro
{
Id = ++id
, ParentId = 0
, EditId = 0
, IdDomains = 2
, UserNick = post.IdUsuario == 1 ? bdvContext.Users.Where(x => x.Id == 2).Single().User : post.Nick?? ""
, IdUsers = post.IdUsuario == 1 ? (int?)2 : null
, Title = post.Asunto?? ""
, Text = post.Texto?? ""
, Closed = post.Cerrado?? false
, Banned = post.Veto?? false
, Remarqued = post.Remarcado?? false
, Deleted = false
, Date = post.Fecha?? new DateTime(2001,1,1)
});
}
}
bdvContext.SaveChanges();
bdvContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT [dbo].[Foro] Off");
transaction.Commit();
}
}
Note, my entityframework was generated by reverse engineering
If you don't want to use EF core's auto-generating primary key values feature, you can turn it off. You can add your data to the primary key It should resolve the error - Set Identity Insert off
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int StudentId { get; set; }
Setting Database Generation option to None helped me. You can find more about it here- https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations
You should keep it off, dont turn it on !
Its turned off for good reasons (security performance)...
Do this instead in your code.
For example, outside your default Create controller when you need to _context.add() a new entry in your DB:
object mytable = new Mytable
{
//as in your model but without key field ! (its readonly)
myvar = "something",
myage = 50,
done = somefunctionToRetrieveData(somevar),
date = system.datetime.now(),
universalAnswer = 42
}
_context.Add(mytable);
await _context.SaveChangesAsync();
When trying to read from CosmosDb i can select a document via:
Id Query
Id + PartitionKey Query
but how do i select data from CosmosDb when i only have the PartitionKey?
using Microsoft.Azure.Cosmos;
public class CosmosDbService : ICosmosDbService
{
private Container _container;
public CosmosDbService(
CosmosClient cosmosDbClient,
string databaseName,
string containerName)
{
_container = cosmosDbClient.GetContainer(databaseName, containerName);
}
public async Task<Error> GetItemAsync(string partitionKey)
{
// selection only via partitionKey - does not work
var response = await _container.ReadItemAsync<Error>(partitionKey, new PartitionKey(partitionKey));
return response.Resource;
// below one works as i am passing the Id (internally generated by CosmosDB)
var id = "2e4e5727-86ff-4c67-84a6-184b4716d744";
var response = await _container.ReadItemAsync<Error>(id, new PartitionKey(partitionKey));
return response.Resource;
}
}
Question:
Are there any other methods in CosmosDB client which can return the document using the PartitionKey ONLY without the need of Id which I don't know ?
When selecting documents you could try to use QueryDefinition + QueryAsync:
var query = new QueryDefinition("select top 1 * from c");
var partitionKey = "PARTITIONKEY";
var resultSet = container.GetItemQueryIterator<ModelObject>(query, null, new QueryRequestOptions { PartitionKey = new PartitionKey(partitionKey) });
var result = new List<ModelObject>();
while (resultSet.HasMoreResults)
{
var item = await resultSet.ReadNextAsync(ct /* CancellationToken */).ConfigureAwait(false);
var itemList = item.ToList();
result.AddRange(itemList);
}
Instead of a top 1 select you could also do a select * (for example)
I am new to asp.net core. I am building a web application for book management. I have a table called Author and books. Being a many to many relationships I made an associative entity that consists of the bookId and authorId. When I try to create I am able to create author and book. I successfully added the author and book to the database.
My author class looks like this
public class Author
{
private int _ID
private string _Name;
public string ID {
get { return _ID; }
set { _ID = value; }
public string Name {
get { return _Name; }
set { _Name = value; }
}
My book class is
public class Author
{
private int _ID
private string _Name;
private string _Title;
public string ID {
get { return _ID; }
set { _ID = value; }
}
public string Title {
get { return _Name; }
set { _Name = value; }
}
public string Name {
get { return _Name; }
set { _Name = value; }
}
I have a data access called db.cs to help to create the book and author in database.
public static int AddAuthor(Author A)
{
int renum = -1;
SqlConnection conn = null;
conn = new SqlConnection(ConnectionString);
conn.Open();
SqlCommand comm = new SqlCommand("sproc_AuthorAdd", conn);
comm.CommandType = System.Data.CommandType.StoredProcedure;
comm.Parameters.AddWithValue("#Name", A.Name);
comm.Parameters.AddWithValue("#Title", a.Title);
SqlParameter output = new SqlParameter();
output.ParameterName = "#AuthorID";
output.DbType = System.Data.DbType.Int32;
output.Direction = System.Data.ParameterDirection.Output;
comm.Parameters.Add(output);
int affect = comm.ExecuteNonQuery();
renum = affect;
c.ID = (int)output.Value;
I have done the same for books as well. I want to fill out the association table as well when the user filled out a book and author using their ID. I tried to do various things like using a cookie to pass data. But I cannot store data. Any kind of help is appreciated. Thanks in advance.
I'm not really sure I understand your last code snippet, but if you're having issues managing your many-to-many relationship between Books and Authors, have you considered just using Entity Framework Core?
Instead of writing a bunch of code that accesses your database, you just create models of your tables (similar to the classes you have defined above), and it handles the many-to-many relationship for you. The code to query for Authors and/or Books could then look as simple as:
using (var db = new dbContext())
{
var books = db.Books
.Where(b => b.ID > 1234)
.OrderBy(b => b.Title)
.ToList();
}
And creating a new Book or Author would be similarly simple:
using (var db = new dbContext())
{
var book = new Book { ID = 1234, Title = "Some Title", Name = "Some Name" };
db.Books.Add(book);
db.SaveChanges();
}
You might have to reimplement a bunch of things to take advantage of Entity Framework Core in your app, but it sounds like it would save you time in the long run.
Using a map in the proto file of grpc for .net core to send a dictionary as a request parameter makes it private field(read-only) in the auto-generated code. So I am unable to assign the dictionary to map and pass it in the API request. How do I make it read-write.?
Sample proto request:
service xyz{
rpc testTrans(TestRequest) returns (TestResponse);
}
message TestRequest {
map<string,string> props = 1;
}
so the auto-generated code looks like this :
public const int PropsFieldNumber = 1;
private static readonly pbc::MapField<string, string>.Codec _map_Props_codec
= new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 10);
private readonly pbc::MapField<string, string> Props_ = new pbc::MapField<string, string>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::MapField<string, string> Props {
get { return Props_; }
}
So now when i try to assign property in request as below, it throws error :
Property or Indexer TestRequest.Props could not be assigned to -- it is read only.
public static void testTrans(Dictionary<string, string> test)
{
var res = client.InitTrans(new TestRequest
{
Props = test
});
}
It seems like there is being prevented when you want to directly declare and initialize the value with:
var res = client.InitTrans(new TestRequest
{
//Property could not be assigned to -- it is read only...error
Props = new Map<string,string>.Add("somekey", "somevalue");
// Alternatively the same problem will also occur when you do
// Props = new Map<string,string>.Add(SomeDict);
}
Instead there should be work around by initializing your variable and then add the value(s) to the dictionary later (after the initialization of the entire message object).
var res = new TestRequest{};
//test is some dictionary
res.TestRequest.Props.Add(test);
//alternatively you can also add with (key, value)
res.TestRequest.Props.Add("someKey", "someValue);
I am currently implementing a Database collection/fixture for my unit tests, as documented on this question here:
xUnit.net - run code once before and after ALL tests
However, instead of using an InMemory Database, I'm using SQLite as InMemory currently has a bug in .Net Core 2.1 which doesn't do a sequence check when using a byte array type
Which leads me to my current predicament, namely that the byte array when you set up a database fixture doesn't get pulled through to the unit test when the context is pulled from the Database Fixture and into the unit test, which is causing concurrency errors when I try to run the tests.
As an example:
Fist set the DatabaseFixture class like so:
public class DatabaseFixture : IDisposable
{
public DatabaseFixture()
{
var connectionStringbuilder = new SqliteConnectionStringBuilder{DataSource = ":memory:", Cache = SqliteCacheMode.Shared};
var connection = new SqliteConnection(connectionStringbuilder.ToString());
options = new DbContextOptionsBuilder<CRMContext>()
.UseSqlite(connection)
.EnableSensitiveDataLogging()
.Options;
using (var context = new CRMContext(options))
{
context.Database.OpenConnection();
context.Database.EnsureCreated();
context.Persons.AddRange(persons);
context.SaveChanges();
}
}
public DbContextOptions<CRMContext> options { get; set; }
public void Dispose()
{
using (var context = new CRMContext(options))
{
context.Database.CloseConnection();
context.Dispose();
}
}
private IQueryable<Person> persons = new List<Person>()
{
new Person
{
Id = 1,
Forename = "Test",
Surname = "User",
RowVersion = new byte[0]
},
new Person
{
Id = 2,
Forename = "Another",
Surname = "Test",
RowVersion = new byte[0]
}
}.AsQueryable();
}
Setup your empty DatabaseCollection class as per the first link:
[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
}
Then set up your unit test to use this Database Fixture:
[Collection("Database collection")]
public class PersonTests : BaseTests
{
private readonly DatabaseFixture _fixture;
public PersonTests(DatabaseFixture fixture)
{
_fixture = fixture;
}
[Fact]
public void SaveAndReturnEntityAsync_SaveNewPerson_ReturnsTrue()
{
{
using (var context = new Context(_fixture.options))
{
var existingperson = new Person
{
Id = 2,
Forename = "Edit",
Surname = "Test",
RowVersion = new byte[0]
};
var mapperConfig = new MapperConfiguration(cfg => { cfg.AddProfile(new InitializeAutomapperProfile()); });
var AlertAcknowledgeService = GenerateService(context);
//Act
//var result = _Person.SaveAndReturnEntityAsync(mappedPersonAlertAcknowledge);
//Assert
Assert.Equal("RanToCompletion", result.Status.ToString());
Assert.True(result.IsCompletedSuccessfully);
Assert.Equal("The data is saved successfully", result.Result.SuccessMessage);
}
}
Now when I debug this, it hits the fixture correctly, and you can when you expand the Results view, the RowVersion variable is assigned correctly:
However, when the data is passed into the unit test, the row version gets set to null:
Any help on this would be greatly appreciated!