I have a table that stores some extra data for some rows of a table like:
public class QuoteExtra
{
[Key]
public int QuoteId { get; set; }
// More fields here
}
I'd like to be able to add rows to this table where I explicitly set the PK.
If I simply leave it as above, setting a value and submitting the row causes the value to be discarded and replaced with the auto-generated value from the database (and the column is defined as an Identity column in the actual schema).
This appears to be the right solution:
public class QuoteExtra
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int QuoteId { get; set; }
// More fields here
}
However this instead gets me the exception:
Cannot insert explicit value for identity column in table 'EnumTest' when IDENTITY_INSERT is set to OFF.
So, how do I write my class so that I'm able to set the value of a Primary Key in EF?
Edit:
I tried adding the following Code-based Migration to set IDENTITY_INSERT to ON:
public override void Up()
{
Sql("SET IDENTITY_INSERT QuoteExtra ON");
}
I ran it and tried again, but got the same exception as above. What's strange is the database does reflect this setting, and running SQL against it directly does allow me to insert arbitrary values in for the primary key - so it would appear Entity Framework itself is enforcing this rule, and neglecting to recognize that IDENTITY_INSERT is not in fact set to off. Do I need to set it somewhere in EF itself?
Edit 2:
I misunderstood IDENTITY_INSERT; I assumed setting it once left it on for that table indefinitely. In fact it lives as long as the "Session," meaning that for example setting it in a Migration means it lives... as long as that Migration runs, and has no bearing on future connections like my later .Add() with EF, which explains why I still got that exception - the DB really is the source of the exception, not EF. Since IDENTITY_INSERT is limited to at most one table per session it's a fairly inefficient way to do this - not creating an Identity PK column in the first place seems like a better route.
This is the proper way of creating a PK without Identity Autoincrement enabled:
public class QuoteExtra
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int QuoteId { get; set; }
// More fields here
}
However, if you add DatabaseGenerated(DatabaseGeneratedOption.None)] after EF Migrations has already created the table, it quietly does nothing to the table. If this is your scenario you need to add a manual migration to drop the table:
add-migration RecreateQuoteExtra
And in the migration:
public override void Up()
{
DropTable("QuoteExtra");
}
EF Automatic Migrations will then automatically recreate the table without the Identity constraint, which will then allow you to set the PK value anytime, without having to run any special commands like IDENTITY_INSERT ON.
It sounds like a less destructive way to do this is coming in EF7 ("Data Motion"), or you could write a lot of manual sql yourself in the migration to create temp tables and move data around if you wanted to avoid losing existing data in the table.
EDIT: Depending on your scenario EF Migrations might not recreate the table - if the class already exists and is already added to your DbContext it will just drop it and leave it at that, meaning your manual migration has to not only drop but also create the table. Not a big deal since the scaffolded code EF Migrations generates for you from add-migration will create these statements for you, but it is a bit more code to check over for issues.
It is right solution but only for a new table. If you change database generated option for an existing table, EF migrations are not able to perform this change and your QuoteId column is still marked as Identity in the database.
I could'nt solve this Problem with your Hints then i've tried to re-create the whole Database but it wasnt working, too.
To fix this you have to remove the identity: true property on the first(!) creation of the Column (e.g. Initial-Migration).
Maybe it will help someone..
Related
I am looking for an appropriate way to expand an existing database, based on entity framework 6 code first implementation, and adding unique values to the new field for every existing row in the table.
So far I have created a migration wich adds the new field.
The Up method looks like this:
Public Overrides Sub Up()
AddColumn("dbo.Customers", "UniqueCode", Function(c) c.String(unicode:=False))
End Sub
I am stuck at the point where the new field should be filled with a unique (calculated) value. To keep it simple, let's say every existing row in the database should be assigned a GUID upon the migration.
Using an SQL statement like this would update all rows with the same GUID. But I need it to be unique for every row.
Sql("Update dbo.Customers SET UniqueCode = '" & Guid.NewGuid().ToString)
Using a foreach in the Up method seems kinda wrong... What is best practice in this case?
In addition: The database I am using is access, so I can't use newid() or random(). The GUID is meant to be a dummy for a programmatically calculated value. It will be a hashed value of some other attributes of the customer. So it must be calculated and updated with migration.
I have found the following approach to be the best fit for my situation. I recommend splitting the database and data changes in 2 migrations, which allows you to use the framework for all changes and be fully up and down compatible.
Here the details to my approach:
Following Bradley Uffner's advice I loop through the data and update it row for row. But, doing this within one and the same migration, throws an error:
The model backing the 'DbContext' context has changed since the database was created. Consider using Code First Migrations to update the database.
Using a DbContext in the middle of it's migration leads to an inconsistent state. The model is already in its after migration state, but the database still has the before migration state in the tables. Model and database do not match, which leads to the above error. To make this work, I would have to disable model checking.
Reference: Change data in migration Up method - Entity Framework
In the above thread I found the suggestion to separate database changes from data changes. That's exactly what I did.
I created one migration to update the database
Public Overrides Sub Up()
AddColumn("dbo.Customers", "WebCode", Function(c) c.String(unicode := false))
End Sub
Public Overrides Sub Down()
DropColumn("dbo.Customers", "WebCode")
End Sub
Run the Update-Database command. And then create a second migration to make the data changes. The Up and Down methods will be empty upon creation. Here is the code I use to update the data row by row.
Public Overrides Sub Up()
Dim DbContext As New Data.DbContext
For Each customer In DbContext.Customers.Where(Function(x) String.IsNullOrEmpty(x.WebCode))
customer.WebCode = GetWebCode(customer)
Next
DbContext.SaveChanges()
End Sub
Public Overrides Sub Down()
Dim DbContext As New Data.DbContext
For Each customer In DbContext.Customers
customer.WebCode = Nothing
Next
MyDbContext.SaveChanges()
End Sub
Some might argue using a simple SQL in the Down method like
SQL("Update dbo.Customers SET WebCode = NULL")
is more efficient. I have tried that, but encountered an error at JetEntityFrameworkProvider.JetMigrationSqlGenerator.GenerateSqlStatmentConcrete which I was not able to locate and fix. It made Visual Studio crash.
If your database server is the SQL Server, you can use the builtin newid() function that generates GUIDs at the database server
https://learn.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql
The query would be
Update dbo.Customers SET UniqueCode = newid()
In case of the SQLite database, use the random() function.
If I already use migrations, I can easily generate incremental one using:
app/console doctrine:migrations:diff.
But assume I have an existing application that does not use migrations yet. doctrine:migrations:diff will just generate a diff between the current database schema and doctrine entities. The problem is I need to have an initial/first migration consisting of CREATE TABLE for every entity created up to this point. My current workaround is to create an empty database, switch credentials in parameters.yml, and run doctrine:migrations:diff then.
I don't like this solution - is there a better one?
you could use doctrine:schema:create --dump-sql to generate the sql for creation and put this into the first migration version
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/tools.html#database-schema-generation
If the table does not exist as a Doctrine Entity, you'll need to manually create a migration class for it, as well as any separate Fixtures.
<?php
namespace DoctrineMigrations;
use DoctrineDBALMigrationsAbstractMigration,
DoctrineDBALSchemaSchema;
class Version00001 extends AbstractMigration
{
public function up(Schema $schema)
{
$this->addSql('CREATE TABLE MY_CUSTOM_PREFIX_example (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB');
}
public function down(Schema $schema)
{
$this->addSql('DROP TABLE MY_CUSTOM_PREFIX_example');
}
}
Also make sure that you exclude these custom tables using filters within your Doctrine configuration (#see: http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html#manual-tables)
For this example you'd replace t_ with MY_CUSTOM_PREFIX_
And what about a little :
bin/console doctrine:migrations:diff --from-empty-schema
With the flag --from-empty-schema it will do exactly what you're asking for.
After that you can (must) manually add an entry in the doctrine_migration_versions table if the DB is already set up and you want to (have to) run /bin/console doctrine:migrations:migrate. Like that (screenshot from adminer):
We have a table, say tbl_X, in our database. This table is in PROD for quite sometime and has approximately 2000 rows. Rows are updated and inserted into this table only once in a while. When this table was created, protection and security were not considered. However,this table consists of data which we think needs some level of protection.
We now want to encrypt the values of some of the columns in the table before saving anything. And we want to decrypt the value before displaying on UI(or before performing any other action).
So the scenario is:
DB server: SQL SERVER 2008
tbl_X Schema:
Id int not null,
Name varchar(100) not null,
CustAccount varchar(100) not null,
CustPrefText varchar(200) not null,
CreatedBy int not null
We want encryption on columns CustAccount and CustPrefText.
We use Linq2SQL to get and set the data in the table. So we are thinking of something achieving the said requirement like this:
public partial class tbl_X
{
public string CustAccount
{
get
{
return Crypter.Decrypt(this.CustAccount)
}
set
{
this.CustAccount= Crypter.Encrypt(value)
}
}
}
Questions:
Is there any better way to handle the change?
Is there a possibility that the existing data in the table will cause any issues while manually updating them?
Will it be required to change the datatypes of the mentioned columns?
Thanks in advance. Please let me know if any other details are required.
AlwaysEncrypted is what you need. It is a client side encryption technology, and will work with ADO.Net SqlClient, and hence will also work with LinqToSql. Here are more details: AlwaysEncrypted client development
However you will need SQL server 2016 for this.
I'm using EF6 Code First.
I have a class library "IdentitySecurity" that contains a context "IdentityDBContext" that points to an "IdentitySecurity" database and the IdentityModels.
I then have my web project that contains a context "ProjectDBContext" that points to a "Project" database and the ProjectModels.
If I create a model in ProjectModels like this:
public class Project
{
public int ProjectId { get; set; }
public virtual IdentitySecurity.Models.ApplicationUser UpdateUser { get; set; }
}
It can't create a migration, I think it is because it can't make a foreign key relationship to another database and expects it to be in the Project database.
The error it gets when you try to create a new migration is this:
One or more validation errors were detected during model generation:
Project.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
Project.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
Another example I ran into similar to this is I had a config table that multiple applications use in a common database area. I attempted to reference this in a model like this:
public virtual Common.Models.CommonItem CommonItem { get; set; }
In this situation, it added the migration and updated the database without error, but what it did is actually create the table "CommonItem" in the Project Database instead of using the one in the Common database.
Is there a way to set up EF6 CodeFirst so I can have configuration tables or ASPIdentity tables in another database, and still reference them as virtual objects?
Thank you.
I'm afraid for foreign key references you'll have to move everything into one DB and have ProjectDbContext to inherit from IdentityDbContext.
Sql Server does not support foreign keys across databases.
I have map the entities in .hmb.xml and define attribute for all entity in classes.
I have some basic accomplishment and get all the record using below code.
public List<DevelopmentStep> getDevelopmentSteps()
{
List<DevelopmentStep> developmentStep;
developmentStep = Repository.FindAll<DevelopmentStep>(new OrderBy("Id", Order.Asc));
return developmentStep;
}
I have check from net that we can write HQL, Now the problem is how to execute this HQL like..
string hql = "From DevelopmentSteps d inner join table2 t2 d.id=t2.Id where d.id=IDValue";
What additional Classes or other thing I need to add to execute this kind of HQL?
Please help me ---- Thanks
To write dynamic queries, I recommend using the Criteria API. This is dynamic, because you have a single query for several different types and you also want to set the ordering dynamically.
The queries are always object oriented. You don't need to join by foreign keys, you just navigate through the class model. There also no "tables" in the queries, but entities.
Getting (single) instances by ID should always be done using session.Get (or session.Load). Only then NHibernate can also take it directly from the cache without database roundtrip, it it had already been loaded.
for instance:
public IList<T> GetAll<T>(string orderBy)
{
return session.CreateCriteria(typeof(T))
.AddOrder(Order.Asc(orderBy))
.List<T>();
}