I just enabled migrations in my project and added a few fields to UserProfile:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Description { get; set;}
public DateTime? CreatedOn { get; set; }
public DateTime? LastAccess { get; set; }
}
I Add-migration AddFieldsForUserProfile and it created:
...
public override void Up()
{
AddColumn("dbo.UserProfile", "Email", c => c.String());
AddColumn("dbo.UserProfile", "Description", c => c.String());
AddColumn("dbo.UserProfile", "CreatedOn", c => c.DateTime());
AddColumn("dbo.UserProfile", "LastAccess", c => c.DateTime());
}
...
Update-database -verbose yielded this output:
Target database is: 'Hifi.Models.HifiContext' (DataSource: (localdb)\v11.0, Provider: System.Data.SqlClient, Origin: Convention).
Applying code-based migrations: [201303311011083_AddFieldsForUserProfile].
Applying code-based migration: 201303311011083_AddFieldsForUserProfile.
ALTER TABLE [dbo].[UserProfile] ADD [Email] [nvarchar](max)
ALTER TABLE [dbo].[UserProfile] ADD [Description] [nvarchar](max)
ALTER TABLE [dbo].[UserProfile] ADD [CreatedOn] [datetime]
ALTER TABLE [dbo].[UserProfile] ADD [LastAccess] [datetime]
[Inserting migration history record]
Running Seed method.
Apparently all went well, but after recieving an error that the coloumn CreatedOn does not exist, I looked into the database with the Server Explorer and indeed, all 4 coloumns are missing in my UserProfile table. What did I do wrong?
Edit
I found my error. Somehow I had two different mdf files aspnet-Hifi-20130330054424.mdf and Hifi.Models.HifiContext.mdf which had the same file size and I assumed both were necessary. My Server Explorer was using the aspnetxx.mdf and the database changes were made to HifiContext.mdf. Shame on me.
On a related note I had trouble correctly displaying a list of all registered users. It was always empty altough I could login flawlessly. Somehow for login aspnetxx.mdf was queried but my MemberListController queried HifiContext.mdf. After changing my connection string I had initially no registered users, new ones were added to HifiContext.mdf and the list worked properly. How did this happen?
are you sure you're looking at the right Db?
it seems so though. Did you get any errors? Any special permissions etc.
My advice is to create a new connection - e.g. config and
<connectionStrings>
<add name="HifiContext" connectionString="Data Source=MACHINE\INSTANCE;Initial Catalog=HiFi;Integrated Security=True; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>`
...and backup your old just in case. i.e. recreate Db from scratch
If nothing works - try recreating if you just turned migrations on - no other ideas.
As for why the out-of-sync happened - hard to say for sure - but I'm guessing you had 'two connection strings' as well (or at some level).
Make sure that you connection string is 'named' the same as your
dbcontext - or put connection at your at DbContext directly
. It is sometimes a problem, as it's not apparent what the EF/CF 'makes' as its default.
call this method in your startup code to have the database recreated with the new fields:
public void CheckForDBChanes()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
}
Related
I have an MVC application that uses entity framework / code first. I'm trying to set up always encrypted in order to encrypt a column (social security number / SSN). I'm running everything in Azure, including using Azure vault to store keys.
I have two models, SystemUser and Person. SystemUser is essentially an account / login which can administer 1 or more People.
The definitions look a bit like:
public class Person
{
[StringLength(30)]
[Column(TypeName = "varchar")]
public string SSN { get; set; } // Social Security Number
...
[Required, MaxLength(128)]
public string SystemUserID { get; set; }
[ForeignKey("SystemUserID")]
public virtual SystemUser SystemUser { get; set; }
...
}
public class SystemUser
{
...
[ForeignKey("SystemUserID")]
public virtual HashSet<Person> People { get; set; }
...
}
I have a very basic page set up that just looks up a user and prints out their SSN. This works. I then adapted the page to update SSN and this also works. This to me implies that the Always Encrypted configuration and Azure Vault is set up correctly. I've got "Column Encryption Setting=Enabled" in the connection string and I encrypted the column SSN using SSMS (I'm using deterministic).
In my SystemUser class I have the following method as an implementation for Identity:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<SystemUser> manager)
{
...
if (this.People.Any())
{
...
}
...
}
This is used for user logins. Running the code results in a:
System.Data.Entity.Core.EntityCommandExecutionException: An error
occurred while executing the command definition. See the inner
exception for details. ---> System.Data.SqlClient.SqlException:
Operand type clash: varchar is incompatible with varchar(30) encrypted
with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name =
'CEK_Auto11', column_encryption_key_database_name = 'xxx')
collation_name = 'Latin1_General_BIN2'
It seems to fail on the line above "if (this.People.Any())". Putting a break point just before that line reveals the following about this.People:
'((System.Data.Entity.DynamicProxies.SystemUser_9F939A0933F4A8A3724213CF7A287258E76B1C6775B69BD1823C0D0DB6A88360)this).People'
threw an exception of type
'System.Data.Entity.Core.EntityCommandExecutionException' System.Collections.Generic.HashSet
{System.Data.Entity.Core.EntityCommandExecutionException}
Any ideas here? Am I doing something that Always Encrypted does not support?
Always encryption is not having support in entity framework. MS still working.
This Blog Using Always Encrypted with Entity Framework 6 explains how to use Always Encrypted with Entity Framework 6 for DataBase first and Code First From existing database and Code first-Migrations with work arounds for different scenarios and problems.
According to https://blogs.msdn.microsoft.com/sqlsecurity/2015/08/27/using-always-encrypted-with-entity-framework-6/
Pass the constant argument as closure – this will force parametrization, producing >correct query:
var ssn = "123-45-6789";
context.Patients.Where(p => p.SSN == ssn);
I am trying to create an EF6 database where two tables, Addresses and Visits, share the same values as primary keys. Visits, conceptually, is an extension of Addresses. I'm splitting the tables because most of the records in Addresses don't require the fields contained in Visits.
I'm using the code first approach. Here's the relevant code for the Addresses:
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey( "ID" )]
public virtual Visit Visit { get; set; }
and for Visits:
public class Visit
{
[Key]
[DatabaseGenerated( DatabaseGeneratedOption.Identity )]
public int ID { get; set; }
[ForeignKey("ID")]
public virtual Address Address { get; set; }
Based on my research, I also needed to include the following in my datacontext's OnModelCreating method:
modelBuilder.Entity<Visit>()
.HasOptional( v => v.Address )
.WithRequired();
Unfortunately, this doesn't work. I can update the database alright, after eliminating scaffolding calls to drop the primary index from Addresses (probably because the add-migration code thinks the primary key is "merely" a foreign key field). But when I run the application I get the following error:
Invalid column name 'Address_ID'.
Invalid column name 'Address_ID'.
From my limited experience with EF6 this looks like someplace deep inside the framework it's expecting there to be fields named 'Address_ID', probably in the Visits table (based on the 'table name'_'field name' naming structure I've seen for other implicitly added fields).
Is what I'm trying to do possible? If so, what am I missing in the configuration?
Additional Info
In trying out bubi's proposed solution, which unfortunately still generates the same error, that I could eliminate the OnModelCreating code and still get functional migration code generated.
Resolution
I finally did what I should've done earlier, which is examine the actual T-SQL code generated by the query which was blowing up. It turns out the problem was not in the Visit/Address linkage, but in a completely separate relationship involving another table. Apparently, somewhere along the way I did something to cause EF to think that other table (Voters) had an Address_ID foreign key field. In reality, the Address/Voter relationship should've been, and originally was, tied to a Voter.AddressID field.
Rather than try to unwind a large number of migrations I opted to blow away the database, blow away the migrations and start from scratch. After recreating the database -- but using bubi's suggestion -- I reloaded the data from backup and, voila, I was back in business.
For the sake of completeness, here's the code I ended up having to put into the OnModelCreating method call to get the Address/Visit relationship to work correctly:
modelBuilder.Entity<Visit>()
.HasRequired( v => v.Address )
.WithRequiredDependent( a => a.Visit );
modelBuilder.Entity<Address>()
.HasRequired( a => a.Visit )
.WithRequiredPrincipal( v => v.Address );
I am a little confused about why I have to use HasRequired in order to be able to use WithRequiredPrincipal/WithRequiredDependent, since not every entry in the Address table has an entry in the Visit table. That would seem to be "optional", not "required". But it appears to work, and maybe the "required" part is just internal to EF's model of the database, not the database itself.
There are 2 problems in the model:
- Only one of the Keys can be autonumbering, the other must get the same Id (this independently by EF).
- A mapping problem.
This model should work.
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Description { get; set; }
public virtual Visit Visit { get; set; }
}
public class Visit
{
public Visit()
{
Address = new Address();
}
[Key]
[ForeignKey("Address")]
public int Id { get; set; }
public string Description { get; set; }
public virtual Address Address { get; set; }
}
Example of use
var visit = new Visit
{
Description = "Visit",
Address = {Description = "AddressDescription"}
};
db.Visits.Add(visit);
db.SaveChanges();
In addition to what bubi mentioned, your modelBuilder statement contradicts the model in that it doesn't mention Address.Visit as the inverse property. So it thinks that the property represents a separate relationship and tries to create the Address_ID column for that relationship.
You need to have
modelBuilder.Entity<Visit>()
// from your description sounds like every Visit needs an Address
.HasRequired(v => v.Address )
// need to mention the inverse property here if you have one
.WithOptional(a => a.Visit);
...or just remove the statement completely since you're already using attributes, and EF should be able to figure it out by convention.
I am using Entity Framework 5 with migrations. My model looks like this:
UserRegistration
Sessions
For each registration there can be many sessions. I was having a problem with a SQL cascading delete error when trying to run migrations, so I attempted to remove the cascade delete by adding the following code:
modelBuilder.Entity<UserRegistration>()
.HasOptional(x => x.Sessions)
.WithMany()
.WillCascadeOnDelete(false);
Now if you know EF you can see an error with that code. I thought it was giving me a 1 to many relationship from UserRegistrations to Sessions, when in fact this code says "Each UserRegistration has an optional Session, each Session has many UserRegistrations". So my 1 to many relationship was going the wrong way. I believe this should have been the code I added.
modelBuilder.Entity<UserRegistration>()
.HasMany(x => x.Sessions)
.WithRequired(x => x.UserRegistration)
.WillCascadeOnDelete(false);
However, when I remove the bad code (first block above), and run add-migration, I get this:
public override void Up()
{
DropForeignKey("dbo.UserRegistrations", "Sessions_Id", "dbo.UserRegistrationSessions");
DropIndex("dbo.UserRegistrations", new[] { "Sessions_Id" });
RenameColumn(table: "dbo.UserRegistrationSessions", name: "Sessions_Id", newName: "UserRegistration_Id");
}
The first two lines (DropForeignKey and DropIndex) looks good, this is removing the foreign key from the UserRegistrations table. The 3rd line, however, comes out of nowhere. There is no Sessions_Id column in the UserRegistrationSessions table. When I run it, I expectedly get an error:
Either the parameter #objname is ambiguous or the claimed #objtype (COLUMN) is wrong.
I'm thinking something is out of whack between my model and my modelbuilder code. Maybe I need to try to make my model look incorrect, but match the modelbuilder code, before moving forward with the fix.
Here is the relevant code in my models:
public class UserRegistration
{
public int Id { get; set; }
public virtual ICollection<UserRegistrationSession> Sessions { get; set; }
}
public class UserRegistrationSession
{
public int Id { get; set; }
public virtual UserRegistration UserRegistration { get; set; }
}
This is more of an answer to the question in the comment, which is 'where is Entity Framework getting its information from'. The answer is probably the serialized version of the model in the resource file attached to the migration.
If you haven't yet deployed the migrations out in the wild, is it possible to remove the offending migration and roll back the DB to before the migration was created?
Table name: TableStatus The tool produces TableStatu with a variable name of TableStatus. For others, TablePerson it creates TablePerson with variable name TablePersons. With Code First you can remove the pluralizations. I found some snippets for both the Entity.tt and Context.tt to remove/add pluralization when you reverse engineer, but neither seem to have any affect on the output classes and DbContext DbSet names. It may be something simple, but I don't see it.
When you do a database-first model, there is an option to pluralize/singularize entity names. Turn this off and it should solve your problem.
You can use the Table attribute to specify the table name.
[Table("account", Schema = "dbo")]
public class Account
{
[Key]
public int id { get; set; }
public string Email { get; set; }
}
Here is the approx. code I am working with.
public class Note {
public virtual Customer Customer { get; set; }
public virtual User User { get; set; }
public ICollection<NoteComment> Comments { get; set; }
}
public class NoteComment {
public virtual User User { get; set; }
}
public class User {
public ICollection<Note> Notes { get; set; }
}
public class Customer {}
// --------------------------------------
public class OurDataContext {
private void ConfigureNotes(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Note>()
.HasRequired<User>(n => n.User)
.WithMany(u => u.Notes)
.Map(a => a.MapKey("UserId"));
modelBuilder.Entity<Note>()
.HasRequired(n => n.Customer)
.WithMany(c => c.Notes)
.Map(a => a.MapKey("idCustomer"));
modelBuilder.Entity<Note>()
.HasMany(n => n.Comments)
.WithRequired()
.HasForeignKey(c => c.NoteID);
/*
modelBuilder.Entity<NoteComment>()
.HasRequired<User>(c => c.User)
.WithMany()
.Map(a => a.MapKey("UserId"));
*/
}
}
}
Note that in the ConfigureNotes() method, the last configuration is commented out. If I leave this commented out, EF will create my tables just fine, but if I uncomment this block, I get the following error:
Unhandled Exception: System.InvalidOperationException: The database creation succeeded, but the creation of the database objects did not. See inner exception for more details. ---> System.Data.SqlServerCe.SqlCeException: The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name = Note_Comments ]
at System.Data.SqlServerCe.SqlCeCommand.ProcessResults(Int32 hr)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommandText(IntPtr& pCursor, Boolean& isBaseTableCursor)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery()
at System.Data.SqlServerCe.SqlCeProviderServices.DbCreateDatabase(DbConnection connection, Nullable`1 timeOut, StoreItemCollection storeItemCollection)
--- End of inner exception stack trace ---
...
What I don't understand is why the navigation property from NoteComment => User is generating a circular reference between Note => NoteComment.
EDIT
For some reason, specifying the FK in the NoteComment class as a nullable property fixed the problem.
public class NoteComment {
public Guid? UserId { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
Then I removed the commented out mapping code in the data context class.
This is not ideal, but I can manage this constraint manually.
SQL Server is very conservative about possible circular references or multiple delete paths compared to other databases.
Yours is originating from multiple delete paths to NoteComment:
Delete User -> Note -> NoteComment
Delete User -> NoteComment
One solution is to remove the Cascade On Delete for User -> NoteComment and do the cleanup manually.
You can also write a database trigger to do the cleanup. Here's an example trigger:
CREATE TRIGGER [dbo].[Users_Delete_Cleanup]
ON [dbo].[Users]
INSTEAD OF DELETE
AS
BEGIN
IF ##ROWCOUNT = 0
RETURN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Delete NoteComment <--> User associations
DELETE nc FROM [dbo].[NoteComment] nc
JOIN DELETED dUser ON dUser.[Id] = nc.[User_Id]
-- Finally, delete user
DELETE u
FROM DELETED dUser
JOIN [dbo].[Users] u ON u.[Id] = dUser.[Id]
END
Edits - additional information:
If you don't have it already, I highly suggest the EF Power Tools extension. This gives you the ability to right click on any class implementing DbContext and get the Entity Framework context menu -
Right click your DbContext class in Solution Explorer -> Entity Framework -> View DDL SQL
That will give you the Sql statement used to generate your entire data model - very useful indeed to see what exactly EF thinks it's building. You can try and run it manually in SqlServer and get a bit closer to the errors that it's running into. When EF is building up the DDL Sql, short of compile errors it will usually get you something (or an entirely cryptic null reference error - then check your Output window), but that something might not run in SqlServer.
Also, you can manually remove the cascade on delete for one to many relationships with the fluent configuration, no need to specify keys unless you want that property:
modelBuilder.Entity<NoteComment>()
.HasRequired<User>(c => c.User)
.WithMany()
.WillCascadeOnDelete(false);
You have a circular reference between User->Note Comments->Note->User->etc..
The you have the Keys setup you you will never stop referencing in the above manner.
There are many different methods to end a circular reference. Such as, [ScriptIgnore] attribute above the properties that are causing a circular reference, or you can do a tree search method where each branch checks to make sure that the object being added is not a parent node (recursively) all the way to the root node of the tree.