Entity framework and migration with datetime - c#

I am using EF 4.3 and the migration script the come along.
But I have an issue with a property that does not get his field created.
public class Test {
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[ScaffoldColumn(false)]
public string Author { get; set; }
[ScaffoldColumn(false)]
public DateTime UpdateUtc { get; set; }
}
When I run the command Add-Migration here is the code that is generate:
public override void Up()
{
CreateTable(
"Test",
c => new
{
Id = c.Int(nullable: false, identity: true),
Author = c.String(),
})
.PrimaryKey(t => t.Id);
}
My first thought was because of the ScaffoldColumn attribute but the Author field is correctly add. The only difference I see is that the type of the field UpdateUtc is not a primitive type.
What would cause this issue?
thanks

Try to add it by hand, using something like:
UpdateUtc = c.DateTime()
I think it should be it. Then update the database using Update command.
When you generate the database, please look at the name of the column generated and see if it is something like [UpdateUtc]. If so, then the name UpdateUtc si reserved and cannot be used.

Related

Entity Framework Cannot insert the value NULL into column Identity Specification set to No

Im using Entity Framework code first and have recently created a new Repo model/table called ImportantCases.
I have set up the configuration and model just like every other however when i get to this line in my code:
public int CreateImportantCase(ImportantCase newImportantCase)
{
_context.ImportantCases.Add(newImportantCase);
_context.SaveChanges(); // <--- here
return newImportantCase.ImportantId;
}
I am getting this error:
Cannot insert the value NULL into column 'ImportantId', table
'MyDatabase.dbo.ImportantCases'; column does not allow nulls. INSERT
fails. The statement has been terminated.
My model/configuration look like this:
Model
public class ImportantCase
{
public int ImportantId { get; set; }
public int EvpId { get; set; }
public string Comment { get; set; }
public int CategoryId { get; set;}
}
EF Configuration
class ImportantCaseConfiguration : EntityTypeConfiguration<ImportantCase>
{
public ImportantCaseConfiguration()
{
HasKey(x => x.ImportantId);
}
}
Prior to calling the create method I am setting up the new ImportantCase via the Post method from the view using a view model and model binding:
if (imp != null ) // already a record, so update
{
imp.Comment = modifiedExceptionPersonViewModel.Comment;
imp.CategoryId = int.Parse(modifiedExceptionPersonViewModel.SelectedCategory);
_service.UpdateImportantCase(imp);
}
if (imp == null) //no record so create
{
ImportantCase newImportantCase = new ImportantCase();
newImportantCase.Comment = modifiedExceptionPersonViewModel.Comment;
newImportantCase.CategoryId = int.Parse(modifiedExceptionPersonViewModel.SelectedCategory);
newImportantCase.EvpId = modifiedExceptionPersonViewModel.EvpId;
_service.CreateImportantCase(newImportantCase);
}
I've inspected the newImportantCase object just before the SaveChanges and it looks as I would expect, with the ImportantId set to '0', usually EF will just create the ID once the write has completed.
One thing I have noticed however is the Identity Specification is set to No when I view the Design of that table, all the other tables that EF has created are set to Yes, what have I done differently?
note
EvpId is the Id of the viewmodel which is being returned from the view, I've just rolled the category and comment properties into this viewmodel in order to deal with them separately in the controller.
edit
I have just realised that I stupidly set the ImportantId to a string when I ran initially update-database but then added a new migration to rectify this later on, not realising EF does not retrospectively sort out the identity specification, is there a way around this?
I did the following to rectify this issue:
1.) Delete the problematic table through management studio.
2.) Make sure the model is amended to have the actual Id (the thing you want as the Identity Specification set to Yes for)
3.) Through the Package Manager Console create a new migration, something like:
add-migration "Set ImportantId as Identity Specification"
4.) If nothings changed you will see an empty Up() and Down() method
5.) Modify these with the contents of the migration that initially introduced this table but make sure you set the Id to an int this time, so this:
public partial class addedimportantcasetable : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.ImportantCases",
c => new
{
ImportantId = c.String(nullable: false, maxLength: 128),
EvpId = c.Int(nullable: false),
Comment = c.String(),
CategoryId = c.Int(nullable: false),
})
.PrimaryKey(t => t.ImportantId);
}
public override void Down()
{
DropTable("dbo.ImportantCases");
}
}
Is copied into the new migration, but slightly altered to this:
public partial class SetImportantIdasIdentitySpecification : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.ImportantCases",
c => new
{
ImportantId = c.Int(nullable: false, identity: true),
EvpId = c.Int(nullable: false),
Comment = c.String(),
CategoryId = c.Int(nullable: false),
})
.PrimaryKey(t => t.ImportantId);
}
public override void Down()
{
DropTable("dbo.ImportantCases");
}
}
In model ImportantCase change int to int?
public class ImportantCase {
public int? ImportantId { get; set; }
public int EvpId { get; set; }
public string Comment { get; set; }
public int CategoryId { get; set;} }

EF Code first set a foreign key with an empty lookup table

I have a problem with EF code first migration related to a lookup table and foreign keys. Let's say I have this two classes in my code:
public class Test
{
[Key]
public long Id { get; set; }
[Required]
public string Title { get; set; }
[Required, DisplayName("Test type")]
public TestType TestType { get; set; }
}
public class TestType
{
public int Id { get; set; }
public string Name { get; set; }
}
TestType is a typical lookup table and I usually fill them up in the Seed() method:
context.TestTypes.AddOrUpdate(
it => it.Name,
new TestType() { Name = "Drug" },
new TestType() { Name = "Educational" },
new TestType() { Name = "Other" }
);
When I create the table with the relationship I get the following migration:
CreateTable(
"dbo.TestTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
AddColumn("dbo.Tests", "TestType_Id", c => c.Int(nullable: false));
CreateIndex("dbo.Tests", "TestType_Id");
AddForeignKey("dbo.Tests", "TestType_Id", "dbo.TestTypes", "Id", cascadeDelete: true);
Now, if I perform the migration of course I will get an error since the foreign key cannot be respected given the fact that the lookup table is still empty and the column created does not have a default value.
In DEVELOPMENT I am able to solve this by simply creating two migrations, the first one to create the lookup table and the second one to set the foreign key. If I run them separately then the Seed method after the first one will fill the table and I can tweak the column creation to pick up the values from the DB to prefill the column before creating the foreign key, a bit like this:
AddColumn("dbo.Tests", "TestType_Id", c => c.Int(nullable: false));
Sql("UPDATE dbo.Tests SET TestType_Id = (SELECT TOP 1 Id FROM dbo.TestTypes)");
CreateIndex("dbo.Tests", "TestType_Id");
AddForeignKey("dbo.Tests", "TestType_Id", "dbo.TestTypes", "Id", cascadeDelete: true);
Then when I run it everything works.
Now, in PRODUCTION I don't have the same luxury, since ALL the migrations are run before the Seed method is run, I will always have the same problem.
I know I could potentially run the migrations in stepped order on the production DB as well but that does not really solve the problem... Let's say a colleague of mine updates his working copy and runs the migrations, all will be run in order and he will encounter the error for sure.
I'm not sure on the current state of your database but I would define your models like this
public class Test
{
[Key]
public long Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
[ForeignKey("TestType")]
public int TestTypeId { get; set; }
[DisplayName("Test type")]
public virtual TestType TestType { get; set; }
}
public class TestType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
Which results in the following migration when the tables don't exist already. I always find describing the foreign keys explicitly works better.
public override void Up()
{
CreateTable(
"dbo.Tests",
c => new
{
Id = c.Long(nullable: false, identity: true),
Title = c.String(nullable: false),
TestTypeId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.TestTypes", t => t.TestTypeId)
.Index(t => t.TestTypeId);
CreateTable(
"dbo.TestTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
}
The seed should then work fine as long as the Test table is empty?

Code first Entity Framework (EF6) Adding Many-to-Many relationship after initial create

I am new to MVC, the Entity Framework, and Databases in general, but I have not been able to figure out what is going on here. I am trying to create a many-to-many relationship via code from an already created db. Thanks in advance for any pointers you can give.
I have a code-first database defined by 2 models (the real one is much more complex, but for brevity this also shows my question/problem):
public class Beer
{
public int BeerID { get; set; }
public string Name { get; set; }
public virtual ICollection<Company> Companies { get; set; } // one beer could have many companies
}
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
// Navigation Property
}
public class ManyToManyDB : DbContext
{
public DbSet<Beer> Beers { get; set; }
public DbSet<Company> Companies { get; set; }
}
When I run the Enable-Migrations -ContextTypeName ManyToManyTest.Models.ManyToManyDB, everything is fine. I get the Configuration.cs file in my project. I do some editing there:
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
Add some data to the Seed method:
context.Companies.AddOrUpdate(c => c.Name,
new Company { Name = "Company1" },
new Company { Name = "Company2" },
new Company { Name = "Company3" }
);
context.Beers.AddOrUpdate(b => b.Name,
new Beer { Name = "Beer1" },
new Beer { Name = "Beer2" },
new Beer { Name = "Beer3" }
);
Now I run "Update-Database -verbose" and the DB is created. So far so good.
Now lets say I forgot to create my Many to Many relationship in the Company class, so I update it:
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
// Navigation Property
public virtual ICollection<Beer> Beers { get; set; } // this is what I forgot, a company can have many beers
}
Ok, so, as this is early on in development, I should be able to just run "update-database" again and it will add the necessary stuff (which in this case will include a new junction table for the many-to-many relationship). Unfortunately, when I do, this happens:
EXECUTE sp_rename #objname = N'dbo.Companies', #newname = N'CompanyBeers', #objtype = N'OBJECT'
Caution: Changing any part of an object name could break scripts and stored procedures.
IF object_id(N'[dbo].[FK_dbo.Companies_dbo.Beers_Beer_BeerID]', N'F') IS NOT NULL
ALTER TABLE [dbo].[Companies] DROP CONSTRAINT [FK_dbo.Companies_dbo.Beers_Beer_BeerID]
It throws this exception
System.Data.SqlClient.SqlException (0x80131904): Cannot find the object "dbo.Companies" because it does not exist or you do not have permissions.
The error being:
Cannot find the object "dbo.Companies" because it does not exist or you do not have permissions.
Any idea why I cannot create a many-to-many relationship after creating the initial db schema?
I may just try again from the start, but wanted to know if there is a solution to this in case I happen upon it in the future.
Using VS2013 and EF6.02 if that matters. The project is from the normal MVC template.
Sorry to say but it seems like a bug in EF.
EF generates automatic update that is equal to the one that would be produced by running Add-Migration.
public override void Up()
{
RenameTable(name: "dbo.Companies", newName: "CompanyBeers");
DropForeignKey("dbo.Companies", "Beer_BeerID", "dbo.Beers");
DropIndex("dbo.Companies", new[] { "Beer_BeerID" });
CreateIndex("dbo.CompanyBeers", "Company_CompanyID");
CreateIndex("dbo.CompanyBeers", "Beer_BeerID");
AddForeignKey("dbo.CompanyBeers", "Company_CompanyID", "dbo.Companies", "CompanyID", cascadeDelete: true);
AddForeignKey("dbo.CompanyBeers", "Beer_BeerID", "dbo.Beers", "BeerID", cascadeDelete: true);
DropColumn("dbo.Companies", "Beer_BeerID");
}
Now in the second line of migration method it calls DropForeignKey that produces ALTER TABLE with DROP that ends with an exception because table was renamed in the first place.
The workaround is to run Add-Migration, drop code and write it by hand. I ended up with code like this:
public override void Up()
{
DropIndex("dbo.Companies", new[] { "Beer_BeerID" });
DropForeignKey("dbo.Companies", "Beer_BeerID", "dbo.Beers");
DropColumn("dbo.Companies", "Beer_BeerID");
CreateTable(
"dbo.CompanyBeers",
c => new
{
Company_CompanyID = c.Int(nullable: false),
Beer_BeerID = c.Int(nullable: false),
})
.PrimaryKey(t => new { t.Company_CompanyID, t.Beer_BeerID })
.ForeignKey("dbo.Companies", t => t.Company_CompanyID, cascadeDelete: true)
.ForeignKey("dbo.Beers", t => t.Beer_BeerID, cascadeDelete: true)
.Index(t => t.Company_CompanyID)
.Index(t => t.Beer_BeerID);
}
Answering my own question. After a few hours of thinking about it, like pg0xC states it is probably a bug in the Entity Framework. Here is an easy workaround in case anyone else hits this problem.
Sticking with my example above, remove both of the ICollections from the Beer and Company classes:
public class Beer
{
public int BeerID { get; set; }
public string Name { get; set; }
//public virtual ICollection<Company> Companies { get; set; } // one beer could have many companies
}
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
// Navigation Property
// public virtual ICollection<Beer> Beers { get; set; } // this is what I forgot, a co
}
Now run update-database again... it worked for me on both the sample as well as my actual code. Of course you will lose any Companies that were linked to the beer class. If this is unacceptable, you will have to do something similar to what the other answerer (pg0xC) stated.
Go back and uncomment the ICollections in both the Beer and Company classes, run update-database one last time and everything should work. After doing this, I had the CompanyBeers junction table in the localdb.

Changing a POCO class name without causing a huge migration

Here's an example of an entity we have inherited:
[Table("Vehicles")]
public partial class Car
{
[Key]
public int Id { get; set; }
[Required]
public Make Make { get; set; }
[Required]
public Model Model { get; set; }
}
We want to refactor our code to rename this table "Vehicle". We can change the [Table] attribute to generate a migration file that does a RenameTable(name: "dbo.Cars", newName: "Vehicles"), all well and good.
However, if we try to change the class name, the migration scaffolder tries to create and THEN delete the same table. Here's a example:
public override void Up()
{
DropForeignKey("dbo.Vehicles", "Make_Id", "dbo.Makes");
DropForeignKey("dbo.Vehicles", "Model_Id", "dbo.Models");
DropIndex("dbo.Vehicles", new[] { "Make_Id" });
DropIndex("dbo.Vehicles", new[] { "Model_Id" });
CreateTable(
"dbo.Vehicles",
c => new
{
Id = c.Int(nullable: false, identity: true),
Make_Id = c.Int(nullable: false),
Model_Id = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Makes", t => t.Make_Id)
.ForeignKey("dbo.Models", t => t.Model_Id)
.Index(t => t.Make_Id)
.Index(t => t.Model_Id);
DropTable("dbo.Vehicles");
}
Is there any way of making a change to the class name in code only (keeping the [Table] attribute the same), without causing this kind of behaviour? Or is this simply something I shouldn't be doing?
You don't have to use the migration as it is being generated. It tries to understand what you changed and create the migration that fits your work, but apparently the algorithm is confused in this case.
You can just alter the migration to execute the RenameTable method. This should work.
Neverless, please submit a bug report to the EF team at http://entityframework.codeplex.com

Where can I learn about EF migration feature that recurses into referenced types?

I just ran into a feature of code first migrations that I didn't realize was there and that's pretty much because everything I know about it comes from a few getting started blog posts.
Is there any more in-depth info on the following behavior (which I find pretty cool because it seems that I can combine it with AutoMapper to simply my web service ETL life)?
For example I have:
public class foo
{
[Key]
public int id { get; set; }
public bar { get; set; }
}
public class bar
{
public int id { get; set; }
public string name { get; set; }
}
public class Context : DbContext
{
public DbSet<foo> Foos { get; set; }
}
Then I run the migration commands:
Enable-Migrations
Add-Migration FirstMigration
And I get:
public partial class FirstMigration : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.foos",
c => new
{
id = c.Int(nullable: false, identity: true),
name = c.String(),
bar_id = c.Int(nullable: false),
bar_name = c.String(),
})
.PrimaryKey(t => t.id);
}
public override void Down()
{
DropTable("dbo.foos");
}
}
Check these two blog posts. They will give you overview of migrations features:
Automatic migrations
Code based migrations
I'm no C# expert and it might be a typo but isn't a property name missing in the foo class for the bar navigation property?

Categories

Resources