Change Code First database table to have PK not be identity column? - asp.net-mvc

I have an MVC application using Code First data migrations and now, long after making a table, I'd like to change the PK column to not be an auto-generated Identity column. But I get the impression I just can't do this without having CodeFirst delete the table somehow (which will be hard given all the dependencies) and recreate it? Really wishing I didn't have to do that.
What I've tried:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AssessmentID { get; set; }
and this in OnModelCreating():
modelBuilder.Entity<Assessment>()
.Property(e => e.AssessmentID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
When doing add-migration, it doesn't add anything. I tried manually adding this line but it does not update the db:
AlterColumn("dbo.Assessment", "AssessmentID", c => c.Int(nullable: false, identity:false));

I've concluded that this is indeed not possible. Like the post below says, there is no SQL Alter command to change the Identity status on a column, so CodeFirst can't create one. I plan to remove all migration files and rescaffold (things have gotten messy in other ways).
Remove Identity from a column in a table

Related

EF6, Oracle, and Identity column

This was working with EF5 but there seems to be an issue with EF6.
We are trying to save a new row to a table using EF6. The primary key column is marked as an Identity value and we have an insert trigger on the table.
When we call db.saveChanges() it always tries to use 0 as the primary key column value.
If we insert a record through Toad it uses the trigger correctly. So the trigger is working.
If we change the trigger to check for 0 instead of null then it also works.
Has anybody else had this issue with EF6?
Thanks,
Joe
With 12c it works fine
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Number { get; set; }

EF Code First Database migration error on second start

I have a web application with local database in production environment. In new build I decided to change database and added database migration.
I ran Enable-Migrations in NuGet console.
Program has generated 201410141412423_InitialCreate.cs file as I already had database - there're some code that initialize my database schema.
Then I added one field in model Workstation
public class Workstation
{
public int Id { get; set; }
[StringLength(15)]
public string Name { get; set; }
public DateTime LastCall { get; set; } //this field was added
public string UserConfiguration { get; set; }
private readonly ICollection<StatusBase> _statuses = new Collection<StatusBase>();
public virtual ICollection<StatusBase> Statuses
{
get { return _statuses; }
}
}
I ran Add-Migration WorkstationLastCallAdded command in NuGet console. New file with migration logic was generated with next code:
public partial class WorkstationLastCallAdded : DbMigration
{
public override void Up()
{
AddColumn("dbo.Workstations", "LastCall", c => c.DateTime(nullable: false));
}
public override void Down()
{
DropColumn("dbo.Workstations", "LastCall");
}
}
I also added next code in Global.asax file to update my database
protected void Application_Start()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<AppDbContext, MigrationConfiguration>());
}
Then I build it and run, and everything works fine.
When I deploy new build to server, there's a database file with some data on the server. The database has old scheme - without LastCall field. So I expect migration updates my database and I won't loose any data.
When I run my site after deploy - everything works fine. Data is not lost and database is updated correctly.
If I restart server or IIS and run my site again - I've got an error.
Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.
When I open local db and watch _MigrationHistory table - there're two rows with 1410151540264_InitialCreate and 201410141956597_WorkstationLastCallAdded migration id's.
Could anybody help me please? Any ideas what's going wrong? Why it works correctly on first run after update but fails on the second?
Thank you in advance.
IIRC, the answer it pretty simple. You have two migrations:
201410151540264_InitialCreate
201410141956597_WorkstationLastCallAdded
You InitialCreate miration is newer than WorkstationLastCallAdded migration. Why? Because InitialCreate is implicitly added to _MigrationHistory table when your DB is created for the first time and you have no migrations. The timestamp for InitialCreate in this case is, of course, equal to current server time. WorkstationLastCallAdded, on the other hand, has a fixed timestamp which reflects the time when you ran Add-Migration WorkstationLastCallAdded command. Therefore, if you create a database after you've created WorkstationLastCallAdded, InitialCreate will be the 'newest' migration.
What happens next? Db initializer searches for the newest migration and finds InitialCreate. Then it compares InitialCreate model hash with current model hash and sees that these hashes are different (of course they are, you have changed your model!). And then you got your error.
The easiest way to solve this is to rename your WorkstationLastCallAdded timestamp (in migration designer file) to something like this:
99999999999999_0001_WorkstationLastCallAdded
A bunch of nines ensures that this migration is older than InitialCreate. 0001 reflects the order of migration. If you want to create another migration, you should name it like this:
99999999999999_0002_SomeOtherFieldAdded
Hope this helps!

"Sequence contains more than one matching element" onload of any Kendo grid

I know this issue has arisen many times on Stack Overflow. I've looked at them, but believe this to be unique:
I'm not using .Single() or .SingleOrDefault() in any LINQ expressions
I checked my models for duplicates, like "Id" and "ID", there are none
This happens onload of any Kendo UI MVC grids, on any table, on any page in my website that has such a grid, and we have several different pages, each with their own grids
Just some history, we just changed some foreign keys to Guids from IDs (ints) in order to point them at different tables in the database than they are currently in the code. Models were updated, accordingly. We also added a view for the Kendo grid to be pointed at, and this was changed in the view. But even grids that have nothing to do with the original or new SQL view/C# models seem to have been affected. Now, during this phase:
public OurDatabase(bool enableLazyLoading=true)
: base("name=OurDBContext")
{
Database.SetInitializer<OurDatabase>(null);
((IObjectContextAdapter)this).ObjectContext.ContextOptions.ProxyCreationEnabled = enableLazyLoading;
((IObjectContextAdapter)this).ObjectContext.ContextOptions.LazyLoadingEnabled = enableLazyLoading;
}
It keeps giving the error "Sequence contains more than one matching element". It will highlight on that middle line with that error.
Can something changing in the database cause this? Code that once worked, and hasn't been changed since that time, now does not, and this is very confusing.
I found out the answers to my problem. Yes, plural.
First, if I commented out the public virtual DbSet<blah> blah { get; set; } in the database entity, and everything that had anything to do with its model, the old code would work again. So that told me the issues were in the model. I also thought I could name "blah" whatever I wanted. I found it should be named after the DB or view name, instead, so I updated that, accordingly.
Second, I found out I had some major issues with my models, which I had used some decorations on with little knowledge behind them. Ex.
[Key]
[Column(name:"GUID", order:2)]
public Guid Guid
It was #2 because ID was #1, and if I put ID in just like above, I got a green squiggly under ID saying 'MyProject.Entities' hides inherited member 'MyProject.Entities.PersistedEntity<int>.Id'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
That was because of the PersistedEntity<int> inherited class that had Id and Name in it, already, that a team member had added. I commented that out and declared the ID and Name columns (which also had the green squiggly until commenting out that class) the normal way.
Then I got an error on the composite keys, saying it could not order them (gee, I wonder why). So these are how they look, now:
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set;}
[Key]
[Column(Order = 1)]
public Guid GUID { get; set;}
[Key]
[Column(Order = 2)]
[StringLength(60)]
public string Name { get; set;}
Which set the ordering and composite key correctly, starting at 0 instead of 1 that I had previously. I had other columns, too, so I continued with setting the [Key] and [Column(Order = x)] attributes on those, too.
Third, I also added a decoration above the class, calling it a table, even though this was for a view (weird):
[Table("My.View")]
Keeping things commented out that relates to adding new models in the controllers seems to be the way to go to troubleshoot this lousy, non-descript error that for me said nothing about the real, underlying issues - at least in this instance. I also didn't think ALL of my grids would stop working just because I added a model - even ones that were not pointed at the new model or the one it was replacing.
After I got the models with the right annotations, I was able to uncomment out the DbSets in my main database model, and because my team member used "Id", when I re-generated the model, I needed to update the ID the grid was using in the Kendo view:
.DataSource(dataSource => dataSource
.Ajax()
.Model
{
.model.Id(p => p.ID)
})
Also, note, I was only able to get it fully working after upgrading to Entity Framework 6.1. Before then, I was getting "Invalid object name 'dbo.My.View'". Apparently in previous versions of EF, you can't just add a model for a table/view and expect it to find it.

Entity-framework code-first migrations NOCHECK constraint?

Is it possible to alter tables in code-first migrations with nocheck constraints? I haven't found any way to do this except of getting SQL script via Update-Database -Script and modifying the sql statements.
You can try creating your own MigrationSqlGenerator and use it with migrations (you can set custom SQL generator in DbMigrationsConfiguration) - I think it should be enough to inherit SqlServerMigrationSqlGenerator and add NOCHECK after adding foreign key = overriding Generate(AddForeignKeyIperation operation).
Anyway using NOCHECK with EF is way to disaster. If you want to have database without checked constraints don't use EF because it will crash every time it reaches inconsistency.
Another way to do it for one-off occasions is to call the SQL for creating the FK manually, like so, from within your Up() method:
// AddForeignKey("dbo.EFElementGroupEntries", "ConstraintCode", "dbo.EFElementConstraints", "Code");
Sql(#"ALTER TABLE [dbo].[EFElementGroupEntries] WITH NOCHECK
ADD CONSTRAINT[FK_dbo.EFElementGroupEntries_dbo.EFElementConstraints_ConstraintCode] FOREIGN KEY([ConstraintCode])
REFERENCES[dbo].[EFElementConstraints]([Code])");
Sql(#"ALTER TABLE [dbo].[EFElementGroupEntries] CHECK CONSTRAINT [FK_dbo.EFElementGroupEntries_dbo.EFElementConstraints_ConstraintCode]");
If the goal is to create a required foreign key but update-database fails due to existing data, just do it in two stages. For example, suppose I want to add a foreign key for TEAM in a PLAYER class for a 1:m relationship where all players must be assigned to a team. Assuming all classes have integer identity primary keys...
1. Add the usual two properties to PLAYER but use a nullable int for the foreign key. ie:
public int? TeamID { get; set; }
public virtual Team Team { get; set; }
Add a migration and update the database. All of the TeamID values will be null but you will be allowed to create the relationship.
Next, fix your data so every player is assigned a valid TeamID. If you are seeding player data, you will need to supply TeamID values there as well.
Modify the PLAYER class so the int is no longer nullable:
public int TeamID { get; set; }
Add another migration and update the database again. You should be good to go.

Change model after database is created on EF4 code only

Hey, sorry for my bad english...
Using EF4 code-only, I have created some POCO classes and my database was generated from that. All worked fine, I inserted some data on the tables but now I need to create a new property on one of my classes. If i just create it, the application give me the exception:
{"The model backing the 'TestContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the RecreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data."}
I tried to create manually the field on the table, but it is still complaining... does someone know if there is a way and if so how can I manually update the database schema (i don't want to recreate it because i already have data) to match the model?
It should work if you make sure that your new column match exactly your new property.
For example, if you add a property NewProp
public class MyEntity
{
[Key]
public int Id;
public string PropA;
public int PropB;
public int NewProp;
}
then in your database table MyEntities, you would add a column NewProp of type int not null.
What you can do to check if the column you add is correct, is to rename your database, then let Code-First recreate the database and see what's different between the original and new databases.
EF generates partial classes. So you can add new properties(fields) in another partial class.

Resources