I have added this computed column inside my data model
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string FullName { get; private set; }
After that I created it inside my database using this query
ALTER TABLE [MyDataBase].[dbo].[User] ADD FullName as ([FirstName] + ' ' + [LastName])
When I run my code I get an error that my database has changed .
My question How to create migration for this computed column (because it's already created using sql query)
Entity Framework doesn't know how to properly handle migrations for computed columns, so you need to help it out.
Firstly, delete the computed column from the table in the database.
Then create a new migration in the package manager console:
add-migration FullNameComputed
Replace the body of the Up() method in the new migration with the following:
Sql("ALTER TABLE [TableName] ADD [FullName] AS ([FirstName] + ' ' + [LastName])");
Finally, run the migration from the package manager console:
update-database
Related
I am using entity framework and Codefirst to create a Stored procedure.
As I reed, we should do some steps in package manager to create SP.
1 - enable migration
2- add-migration MYclass
3- update-database
and in Myclass(new created) I write my SP code in UP() method to create SP. works fine!! BUT when I change SP and run update-database again it does not work and I need to do another add-migration command to create new MYclass2. Is that right? I mean every time I should write add-migration?
this is mycode
public override void Up()
{
Sql(#"Create procedure testSp
as
select std.Id as stdName, std.Name as MajorName, mj.Name from dbo.Students as std
inner join dbo.Majors as mj on std.Id = mj.Id
");
}
public override void Down()
{
Sql("drop procedure testSp");
}
when I run update-database again the result is "No pending explicit migration"
even if I change the SQL query to "Alter procedure...." it does not work , no change happens.
thanks
EDITED
consider this scenario, I want to change my SP name(just an example)
so I need to change the query to "Alter store procedure tespSP2 ..."
or any other change, should I run add-migration again?? or update-database is supposed to do it??
in entity framework migrations added to a _migrationHistory table, you can delete the last row of this table [it's not recommended]
or you can use rollback/undo command
Update-Database -TargetMigration:MigrationsName
then use update-database -force
Somehow either, my C# code, or entity framework 6 is dropping and creating a database when I run
PM> update-database -verbose
from an explicit migration with an up() method that looks like this...
public override void Up()
{
AddColumn("dbo.Term", "Term_Id", c => c.Int());
CreateIndex("dbo.Term", "Term_Id");
AddForeignKey("dbo.Term", "Term_Id", "dbo.Term", "Id");
}
-verbose generates this...
Origin: Configuration).
Applying explicit migrations: [201410271927053_addTermsTable2].
Applying explicit migration: 201410271927053_addTermsTable2.
ALTER TABLE [dbo].[Term] ADD [Term_Id] [int]
CREATE INDEX [IX_Term_Id] ON [dbo].[Term]([Term_Id])
ALTER TABLE [dbo].[Term] ADD CONSTRAINT [FK_dbo.Term_dbo.Term_Term_Id] FOREIGN KEY ([Term_Id]) REFERENCES [dbo].[Term] ([Id])
INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
(plus the migration insert statement)
None of which indicates (to me) the db is about to be dropped.
Can someone confirm this does not drop?
Does it matter that
this is an Azure SQL database?
that the columns were added in response to adding this.. to the class?
public virtual ICollection<Term> urls { get; set; }
Any pointers on how to make sure I know when a drop create is going to occur?
Thanks.
In our project we have necessity of adding some predefined data to DB. I think the best way and concept is using for that EF Migrations (not Seed method).
But we have a big troubles with adding related data to DB:
For Example:
Suppose we have 2 tables:
Users:
Id (PK auto increment)
Name
RoleId
Roles:
Id (PK auto increment)
Name
Let's suppose that we need to add User(Name = 'John', RoleId = (Id of role that name is 'Admin')).
How can we do it? It would be great if we find a solution that allows us to execute pure SQL SELECT script which not uses Entities of Code First because they can be modified or removed.
For DELETE, INSERT, UPDATE can be used Sql(...) method but what about SELECT?
You cannot have a context into the migration.
Logically first are ran the migrations to Update the DB Schema, then you can have a context to work with the data via it. If your DB does not match the model, or even the table is still not there, you cannot use it in EF.
I had to look into the EF code (and also because was curious). Practically the Sql() method in the DbMigration class in several levels below just adds the SQL string into a list of queries that should be executed into the transaction and moves on. It does not executes it when it is called. So in short EF just fills in a list of codes lines that should be executed in the end at once. And it seems correct if you try to walk in all paths of what you can do with the C# code in the migration code.
The question is quite good actually, unfortunately still I didn't found any better solution rather than using pure ADO.
Another option is to generate more custom SQL queries, and use T-SQL more widely.
For your case as you want to insert the user and set the groupId looking by the name, it can be used with inner select:
INSERT INTO Users (Name, GroupId)
VALUES ('John', RoleId = (SELECT Id FROM Roles WHERE Name = 'Admin')).
For my issue, I had to a bit do more sophisticated execution - the following does the same as the AddOrUpdate method of the DbSet, using the IF statement:
IF EXISTS (SELECT * FROM Table1 WHERE Column1='SomeValue')
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
ELSE
INSERT INTO Table1 VALUES (...)
I found it here: http://blogs.msdn.com/b/miah/archive/2008/02/17/sql-if-exists-update-else-insert.aspx
I'm using good old LINQ for this:
public override void Up()
{
using (var dc = new DbContext("your connection string or name"))
{
var ids = dc.Database.SqlQuery<int>("SELECT id FROM sometable WHERE somefield={0}", 42).ToArray();
...
}
}
Using LINQ is better, even for usual migrations, because, there is a bug in DbMigration.Sql method, it ignores arguments: How to pass parameters to DbMigration.Sql() Method
I try to change MaxLength property from 100 to 50 and i got exception that Says
"The index 'IX_Singers_Name' is dependent on column 'Name'.
ALTER TABLE ALTER COLUMN Name failed because one or more objects access this column."
Mode is :
public class Singer : NamedEntity
{
[MaxLength(50)] // It was 100
public override string Name { get; set; }
}
As i understand, entity framework needs to alter table for this change but it can't alter table because an index exist on Name property. So how i can make it possible with entity framework migrations ?
I can possibly drop index in migration then change maxlength in next migration and create index the last migration again. But i believe that there should be exist an easy way to change that attribute value.
In SQL Server, indexes are pretty much like tables themselves. So if you've got the column in an index, both that index and the table would need to be modified. I agree that where EF migrations were scaffolded to add the index (e.g. for a foreign key) they should also take care of removing and reapplying the index. However, in this instance the index would have had to have been added manually. Therefore it will need to be maintained manually in the migration. Note that it can be done in a single migration:
public override void Up()
{
DropIndex("dbo.Singer", new []{"Name"});
/* Code to alter the table */
CreateIndex("dbo.Singer", "Name");
}
Don't forget to put this in both the Up() and Down() methods.
I have added a (bit\bool) column IsController to one of my tables
ALTER TABLE P_USER ADD IsController bit NOT NULL DEFAULT 0
Updated the edmx and added IsController to the MY_USER entity, then changed its name to
IsControllerX and mapped it to the IsController from the table.
And set this inside the solution.domain.business cs file:
public virtual bool IsControllerX { get; set; }
On debug I have the error:
An error occurred while executing the command definition. See the
inner exception for details. InnerException: Invalid column name
'IsController'.
The error is with the IsController and not with IsControllerX! That is the name of the column that I mapped to - the name of the column inside the database!
Can someone please explain why I get this error?
HOW did you update your model and your generated classes??
In the EDMX, you should select the Update Model From Database option from the context menu, and then in the Update Wizard, you should pick your table that has been modified:
Doing this will properly update your EDMX and it works just fine in my scenario. Did you do it this way, and it still fails?? Or did you just do it manually ??