DbMigration in ef code first 4.4 - entity-framework

we are using ef code first 4.4 with db migrations. I have an entity called Paypal in our DbContext. When I run the Update-Database command from package manager console, it generates the db but then throws exception with message
There is already an object named 'PayPal' in the database.
When I inspected the sql statements in package manager console using verbose command, there were two commands for creating paypal table, one from InitialCreate.cs in Migrations folder and other from test.cs in the same folder.
Edit 1:
The Up method in both DateTime_InitialCreate.cs and DateTime_test.cs contain following first entry.
CreateTable(
"dbo.PayPal",
c => new
{
Id = c.Int(nullable: false, identity: true),
ActionUrl = c.String(),
Cmd = c.String(),
Price = c.String(),
Interval = c.String(),
IntervalType = c.String(),
AutoRecurring = c.String(),
Business = c.String(),
Return = c.String(),
CancelUrl = c.String(),
NotifyUrl = c.String(),
PlanName = c.String(),
Amount = c.String(),
CurrencyCode = c.String(),
})
.PrimaryKey(t => t.Id);
When inspecting the code, the both files seem identical with no difference at all.
What should I do to solve this issue?

If I'm reading this correctly (and correct me if I'm wrong), you are trying to create the table in both locations without checking if it already exists. In which case, when you run Update-Database, it's trying to create it twice because it finds it in both files. At which point you're getting an error for it already being there.
You need to put in a check to make sure the table doesn't already exist into both files to prevent this from happening.
Let me know if I'm reading this wrong.

Related

Entity Framework change Key Type

I have created a model with various values but stupidly used a GUID for my key, I am currently attempting to change that to an Int but am getting an error when I do so.
I have run the enable migration command:
Enable-Migrations -Force -ContextTypeName project.Models.MyContext
This creates the migration I would expect but when I run:
Update-Database -Force
The error I'm getting is:
Operand type clash: uniqueidentifier is incompatible with int
I don't care about the data currently contained within the database since it is just using a SQL Server Express database just now, but I would prefer to find a way to migrate this instead of just having to drop the DB altogether, what's the best way to do this?
I have already got
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
in Global.asax.
I would expect that the generated migration is using AlterColumn to try and change the type of the field from guid to int. This is not possible, so you'll need to modify the generated migration yourself:
Assuming your table is dbo.People and the key is called Id, you probably have this at the moment:
DropPrimaryKey("dbo.People");
AlterColumn("dbo.People", "Id", c => c.Int(nullable: false, identity: true));
AddPrimaryKey("dbo.People", "Id");
Change it to:
DropPrimaryKey("dbo.People");
DropColumn("dbo.People", "Id");
AddColumn("dbo.People", "Id", c => c.Int(nullable: false, identity: true));
AddPrimaryKey("dbo.People", "Id");
Note that if you've got this key referenced elsewhere, this technique will not work if you've got any data present, as the keys are all being regenerated.
Update for EF Core generated migrations:
dotnet : System.Data.SqlClient.SqlException: Operand type clash: int is incompatible with uniqueidentifier
change
migrationBuilder.AlterColumn<Guid>(
name: "VATID",
schema: "catalogue",
table: "Products",
nullable: false,
oldClrType: typeof(int));
into
migrationBuilder.DropColumn(
name: "VATID",
schema: "catalogue",
table: "Products");
migrationBuilder.AddColumn<Guid>(
name: "VATID",
schema: "catalogue",
table: "Products",
nullable: false);
Of course, this will destroy your data for the certain column. But they obviously cannot be converted into GUID.
I am trying to add something to the selected answer since I don't have enough reputation to add comment there :
Please also add code to drop and recreate indexes if any else it will fail to drop column. e.g.
DropPrimaryKey("dbo.People");
DropIndex("IX_...") // If exists before
DropColumn("dbo.People", "Id");
AddColumn("dbo.People", "Id", c => c.Int(nullable: false,
identity: true));
AddPrimaryKey("dbo.People", "Id");
CreateIndex("IX_...", unique:(true/false)) // If existed before
The AlterColumn will Drop and Add keys (primary,foreign etc) but will not touch indexes. I have faced this.

Azure - Code First Migrations not working correctly

I am trying to initially create a sql server db schema for my azure application with code first migrations (as described here).
The basic creation of my tables works, however the azure (entitydata) specific things don't. There is no default value for CreatedAt, no UpdatedAt Trigger and also a problem with a clustered index. This happens to all of my tables. Thats what i am doing (shows the problem for 1 Table Account):
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetSqlGenerator("System.Data.SqlClient", new EntityTableSqlGenerator());
}
var migrator = new DbMigrator(new Configuration());
migrator.Update();
The up-Method in my DBMigration-Class looks as follows:
CreateTable(
"dbo.Accounts",
c => new
{
Id = c.String(nullable: false, maxLength: 128),
Username = c.String(nullable: false, maxLength: 30),
Salt = c.Binary(),
SaltedAndHashedPassword = c.Binary(),
MailAddress = c.String(),
FacebookId = c.String(),
Version = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
CreatedAt = c.DateTimeOffset(nullable: false, precision: 7),
UpdatedAt = c.DateTimeOffset(precision: 7),
Deleted = c.Boolean(nullable: false),
})
.PrimaryKey(t => t.Id)
.Index(t => t.CreatedAt, clustered: true);
I thought, that the EntityTableSqlGenerator should do these azure specific things, however it seems that it changes nothing.
I had the same issue few days ago and solved it temporarily as described below: I think Microsoft EF team should solve it permanently.
According to my temporary solution, you need to make some modifications before execute your migration file.
First, you need to cancel clustered index decalarations for CreatedAt properties for all entities which is inheriting from EntityData base class.
Id, CreatedAt and Deleted fields need to be decorated with default value declarations.
You can add following lines below each create commands in your migration files.
You can get additional ideas from here

How to successfully do delete/remove operation in ManyToMany relationship?

I'm using ManyToMany with JPA annotation, I need your valuable suggestions.
(Assume Person and Address. Same Address is referred to more person (living at same address)). I have to delete a person from that address.
Person p1 = new Person();
Person p2 = new Person();
Address add1 = new Address();
p1.add(add1);
p2.add(add1);
As well doing
add1.add(p1) ;
add1.add(p2) ;
THen on merge or persist iit mapped appropriately.
p1 - add1
p2 - add1
I have to delete p2 alone , when i did
p2.removeAddress(add1)
removeAddress(add1) {
addColelction.remove(add1) }
What happens is it deleted the entry for address and again by Hibernate jpa provider again tries to persist at Address entity and says "deleted entity passed to persist " and henc transaction roll back happens.
My correction on the question. The mapping exist as
In Script side :
#ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})
#JoinTable(name = "XXXX", joinColumns = { #JoinColumn(name = "X1_ID", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "X1_ID", nullable = false, updatable = false) })
#org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Collection<Parser> parsers;
In Parser side
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "parsers")
private Collection<Script> scripts;
The data saved as
Script1 - Parser1
Script2 - Parser1
Our data model is Object A has oneTomany to B , B has oneTomany to Script objects.
Say collection of A has (B1,B2,.....)
B1 has (Script1)
B2 has (Script2)
When we want to delete that B2 object (we do just EM.merge(A)), we want the particular B2 from the collection has to be deleted and the related the Script2 has to be deleted. Script2 delete should remove the intermediate entry alone but should not delete the Parser.
But Parser1 gets deleted and Transaction gets rolled back saying ''deleted entity passed to persist
Please share your ideas.
You mention you only want the join table cleared up, but you have both DELETE_ORPHAN and cascade all set on the Script->Parser mapping. The first setting seems to be a hibernate option equivalent to JPA's orphan removal, which will cause any entities de-referenced from the collection to be deleted in the database. This will cause Address1 in the example to be deleted.
The cascade all option will force the remove operation to be cascaded to any entities still referenced by Person/Script when remove is called on Person/Script. In the first example this will cause Address2 to be removed/deleted from the database.
If you want address 1 or address2 to survive, then remove the appropriate setting. As mentioned in comments, you will also want to clean up your references, as the survivors will be left referencing a deleted Person/Script entity which may cause problems in your application.

EF5 Database Migrations: How to move data

I'm using EF5 code first and now I need to update my database so I enabled database migrations and added a migration but the generated code was not what I needed. This is the code:
public override void Up()
{
CreateTable(
"dbo.HistoricalWeightEntities",
c => new
{
PatientMedicalDataId = c.Guid(nullable: false),
Id = c.Guid(nullable: false),
Weight = c.Single(nullable: false),
Date = c.DateTime(nullable: false),
})
.PrimaryKey(t => new { t.PatientMedicalDataId, t.Id })
.ForeignKey("dbo.PatientMedicalDataEntities", t => t.PatientMedicalDataId, cascadeDelete: true)
.Index(t => t.PatientMedicalDataId);
AddColumn("dbo.PatientDataEntities", "PatientDataFilePath", c => c.String());
//Here I need to move data from the old Weight column to the Weight column on the newly
//created table and create the id (Guid) and the foreing key before the old
//column is dropped
DropColumn("dbo.PatientMedicalDataEntities", "Weight");
}
What I need to do is to add some sql script that move data from the 'Weight' column in the dbo.PatientMedicalDataEntities to the Weight column in the newly created table dbo.HistoricalWeightEntities and also insert the Id value (key) which is a Guid and the corresponding foreign key before the column is dropped.
Can somebody show me how to do this is sql?
Thank you in advance
It should be something like that (donnow what you wanna do with the Date column)
Sql("INSERT INTO HistoricalWeightEntities(Id, Weight, PatientMedicalDataId) "+
"SELECT newid(), Weight, <theForeignKeyColumn> from PatientMedicalDataEntities");

Entity Framework auto incrementing field, that isn't the Id

I know this isn't the most ideal solution, but I need to add an auto incrementing field to one of my EF Code First objects. This column id NOT the Id, which is a guid.
Is there anyway for me to define the auto incrementing field in code, or would creating the column myself and defining in the DB that its auto incrementing work?
You can annotate that property with DatabaseGenerated(DatabaseGeneratedOption.Identity). EF allows only single identity column per table.
public class Foo
{
[Key]
public Guid Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Bar { get; set; }
}
Old post thought I would share what I found with Entity Framework 6.1.3.
I created a simple data layer library using C# and .NET Framework 4.6.1, added a simple repository/service class, a code first context class and pointed my web.config file to a local SQL Express 2014 database.
In the entity class I added the following attribute constructor to the Id column:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
Then I created a new migration by typing the following in Visual Studio 2015 Package Manager:
Add-Migration
Give the migration a name and then wait for the DbMigtation class to be created. Edit the class and add the following CreateTable operation:
CreateTable(
"dbo.Article",
c => new
{
Id = c.Guid(nullable: false, identity: true),
Title = c.String(),
Content = c.String(),
PublishedDate = c.DateTime(nullable: false),
Author = c.String(),
CreateDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => t.Id);
}
The above table is an example the key point here is the following builder annotation:
nullable: false, identity: true
This tells EF to specifiy the column as not nullabe and you want to set it as an identity column to be seeded by EF.
Run the migration again with the following command:
update-database
This will run the migration class dropping the table first (Down() method) then creating the table (Up() method).
Run your unit tests and/or connect to the database and run a select query you should see your table in its new form, add some data excluding the Id column and you should see new Guid's (or whatever data type your choose) to be generated.
For those stumbling onto this question for EF Core, you can now create an auto-incrementing column with your model builder as follows:
builder.Entity<YourEntity>().Property(e => e.YourAutoIncrementProperty).UseNpgsqlIdentityAlwaysColumn();
Reference: https://www.npgsql.org/efcore/modeling/generated-properties.html