EF 5 will not set a PK property to IsIdentity to false - entity-framework

The answer in this thread is not working for me.
I put this annotation on the PK in my customer class like so.
public class Customer
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
The database migration creates a configuration showing this one line for the newly added data annotation:
AlterColumn("dbo.Customers", "Id", c => c.Int(nullable: false));
I run the migration and look at the table in SQL Server Management Studio. The customer Id column still has Identity Specification Yes and Is Identity Yes. What am I doing wrong?
Thanks.

You are not doing anything wrong. That is a limitation (or maybe it can be considered as a bug) of migrations because SQL server doesn't allow changing IDENTITY on existing columns. It can be set only on new columns. If you change identity value in management studio it will internally execute some complex SQL batch involving temporary table and a lot of data manipulation.
The simplest solution is to delete your database and remove identity definition from your initial migration. Otherwise use SQL profiler to see what SQL management studio is doing when changing column's identity value and use that SQL in your migration instead of AlterColumn.

The EF treats the Id field as a PK, and a PK must have unique values. That what Identity Specification means. Table Column Properties
Setting DatabaseGeneratedOption.None only specifies that the Id will not be generated by the DB Engine, and you will have to provided it (which I don't think is a good idea).

Related

How does EF Core build its internal model?

Background:
We're doing an annoying merge due to a poor branching strategy. Note: all code is pseudocode
We updated an entity class to change the Submittal table. We removed the specific report Id and it's foreign key and replaced it with a generic 'ReportId' with no foreign key.
public class Submittal{
int Id {get;set}
string Status {get;set;}
int SpecificReportId {get;set}
}
There were some migrations that were applied that changed the db (db has the updated column and no FK)
The db context has no reference to the old column. The entity now looks like:
public class Submittal{
int Id {get;set}
string Status {get;set;}
int ReportId {get;set}
}
The modelBuilder in the context has no reference to the old column name.
The model snapshot with the migrations has no reference to the old column name.
The repository method for adding the submittal:
public async Task AddSubmittal(Submittal submittal){
using var context = new ReportContext(dbContextOptions);
context.Add(model);
context.SaveChangesAsync();
}
When debugging, the submittal object has ReportId and no SpecificReportId, but when it tries to run SaveChangesAsync() it fails with an exception of "SqlException: Invalid column name 'SpecificReportId'.".
The dbOptions connection string is pointing at the database I expect, and when I ran sql profiler I got the following sql for my query:
INSERT INTO [Schema].[Submittal] ([Status], [SpecificReportId], [ReportId])
VALUES (#p0, #p1, #p2);
SELECT [Id]
FROM [Schema].[Submittal]
WHERE ##ROWCOUNT = 1 AND [Id] = scope_identity();
What the heck is going on? It feels like I must have missed some piece of how the internal model is generated. I have searched the code for the original id, but did not see anything that looked related.
Notice that the query is trying to insert both ReportId and SpecificReportId. That means you have some lost (or inherited) public SpecificReport SpecificReport { get; set; } inside Submittal class (or opposite reference in SpecificReport class), and EF creates shadow foreign key for it. Full dump of what EF knows about your model is available in DbContextModelSnapshot.cs file, updated with each migration (try adding new migration and make sure it's generated as empty, before you rely on it).
Your pseudocode should work as posted, there must be something else in your project.
PS: you can also set Microsoft.EntityFrameworkCore.Database.Command log level to information, as another debugging tool.

One to One Relationship between primary key and unique key in EF6

I'm trying to create a One-to-One relationship between two tables using a primary key and a unique key of the two tables (rather the primary keys).
The following is what I'd like to work.
// The principal end
public class A
{
// The primary Key
public int AId { get; set; }
// The navigation property
public virtual B B { get; set; }
}
// The dependent end
public class B
{
// The primary Key
public int BId { get; set; }
// The unique key
[Index(IsUnique = true)]
public int AId { get; set; }
// The navigation property
public virtual A A { get; set; }
}
But then I see this error:
Unable to determine the principal end of an association between the types 'A' and 'B'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I'm quite sure a primarykey-uniquekey relationship is allowed in SQL Server. Looks like EF6 doesn't support it. EF Core 1.0 seems to, but it's not feasible to port to EF Core right now.
Why we need a need a relationship of this kind:
We have two tables A and B in production, but the one-to-one relationship, which should have been there is missing. The relationship is something we need so we can navigate from an A object to a B object with EF. Since both tables have values, we can't really make the primary key, the foreign key - we'll end up with incorrect data.
My approach to fixing this was to:
add a column
fill it with the correct A ids
make it unique
establish the 1-1 relationship
An alternate approach to fixing this is more than welcome.
This is possible with EF Core using Fluent API's .HasPrincipalKey() method. Unfortunately not supported in EF6 which is a shame as relationships over unique keys can essentially be treated the same as foreign key constrains so I'd imagine it would have been an easy addition.
Now that MS has forgot about EF6 and is focusing on EF Core, this will never happen. I really liked using the visual entity designers as it saved so much time. Looking at the thousand+ lines of code the EF Core DbContext scaffold generator spits out for me is discouraging to say the least. Sure, it's pretty when you're dealing with a demo project consisting of two cute tables but we all know this is never the case in the real world. The whole point of using an ORM is to save time but I'm not sure if having to manage thousands of lines of configuration code is any better. Just by two cents.

How to alter relationship keeping existing data in entity framework code first?

I have two entities
public class Account
{
[Key]
public int Id { get; set;
public int MemberInfoId { get; set; }
public Member MemberInfo { get; set; }
//Other Properties
}
public class Member
{
[Key]
public int Id { get; set; }
//Other Properties
}
With following relationship
modelBuilder.Entity<Account>()
.HasRequired(a => a.MemberInfo)
.WithMany()
.HasForeignKey(a => a.MemberInfoId)
.WillCascadeOnDelete(true);
However, an Account has one Member only so the following relation is better suited (I guess)
modelBuilder.Entity<Account>()
.HasRequired(a => a.MemberInfo)
.WithRequiredPrincipal()
.WillCascadeOnDelete(true);
But code first migration won’t migrate to that. It gives the following error
The object 'PK_dbo.Members' is dependent on column 'Id'.
The object 'FK_dbo.Accounts_dbo.Members_MemberInfo_Id' is dependent on column 'Id'.
ALTER TABLE DROP COLUMN Id failed because one or more objects access this column.
What can I do to alter the relation without recreating the database to keep the already inserted data?
First, you can read this page on mixing code-based migrations with automatic migrations to see if you even want to go this route in the first place. Generally, it's not a good idea if you have a team involved.
Next, it might be good to know that if you change the relationship between Member and Account to a one-to-one, Entity Framework requires that the primary key on the dependent side also be the foreign key. The column that used to be the primary key on the dependent side will become useless from EF's perspective. You also won't need the Account.MemberInfoId anymore, either.
Finally to create a migration, after you finish modifying the models, you can run Add-Migration with a migration name. This will create a migration file with a DbMigration class that you can modify. You'll probably need to do something like the following:
Create a new column in Member that will hold the new foreign key
Use Sql() to update values in that column with the primary key of the associated account
Drop the foreign key constraint, index, and primary key
Drop the account.memberinfo_id column and member.id column (which is optional, but if you don't drop the member.id column, you'll have to make sure to map the model's Member.Id property to the column created above).
Rename new column in member to id
Add primary key to new column in Member
Add index and foreign key
I'm sure I've missed something, but that's the general gist. I'd probably also backup everything, since something's guaranteed to go wrong the first five times or so.

How to add Foreign Key Properties subsequently to a Code First Model?

Given the Model:
Public Class Customer
Property Id() As Guid
Property FirstName() As String
Property MiddleName() As String
Property LastName() As String
Property Addresses() As ICollection(Of Address)
End Class
Public Class Address
Property Id() As Guid
Property Name() As String
Property Street() As String
Property City() As String
Property Zip() As String
Public Property Customer() As Customer
End Class
Entity Framework 6 Code First has created a column called Customer_Id in my table Addresses. Now, I'd like to add a Property Customer_Id to my class Address that represents the existing foreign key relation:
Public Class Address
Property Id() As Guid
Property Name() As String
Property Street() As String
Property City() As String
Property Zip() As String
Public Property Customer() As Customer
//Added
Public Property Customer_Id() As Guid
End Class
Unfortunately this results in an InvalidOperationException while creating the DbContext saying:
The model backing the 'DataContext' context has changed since the database was created.
I tried different property names (with and without underscore, different casing). But still no luck. So, what is the correct way to add those properties subsequently without the need for migrations? I assume it's possible, because the model does not really change, I am only changing from an implicit declaration of a property to an explicit...
Update:
The responses show me, that I did not explain the problem very well. After some more reading I found the correct names now: I have an application which is installed several times at customer locations (therefore dropping and recreating the database is no option). Currently, it depends on Entity Framework's Independent Associations, but I want to have the Foreign Key in my entity as well (this is no change to the model, the foreign key is already there, but does not exist as a property in my entity, since this is currently only relying on the IA instead). I did not manage to add it without EF thinking my Database is outdated.
for me two ways :
drop table __MigrationHistory : that is have the new model runs, but forget migration functionalities
create a new db by changing the connection string of the application. Replace old __MigrationHistory by __MigrationHistory of the newly created db
Never tested the second solution, but it should work.
Before using any solution:
backup you db.
Before using first solution: are you sure you will never need migration functionalities ?
This exception is because you change your model. You have to set migration strategy. Please look at:
http://msdn.microsoft.com/en-us/data/jj591621#enabling
(edited)
First of all you have to remove that exception. Even if you didn't add any new column to your database your model has changed because you added new property to Address class. If you check your DB you will find dbo.__MigrationHistory table with Model column. Last (earliest) value from that column is used for checking that your model and DB are compatible. I'm not sure but I think that EF stores there binary serialized model. So the solution is - recreate DB or add migration (probably empty migration).
(edited)
When you want to set FK you can do this very simple by Data Annotations
// c# example
public class Address
{
...
public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
}
or in fluent api
// c# example
modelBuilder.Entity<Address>()
.HasRequired(arg => arg.Customer)
.WithMany()
.HasForeignKey(arg => arg.CustomerId);
or look at:
http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx
http://msdn.microsoft.com/en-us/data/hh134698.aspx

Why is entity framework not annotating some non nullable columns as required?

I am using EF 4.1 with database first.
Example table:
CREATE TABLE dbo.Foo(
[ID] [int] IDENTITY(1,1) NOT NULL,
Created datetime not null default(getdate()),
Title varchar(80) not null
PRIMARY KEY CLUSTERED ([ID] ASC)
)
EF correctly loads the model with all 3 columns as nullable = false.
Output from code generation item "ADO.NET DbContext Generator":
public partial class Foo
{
public int ID { get; set; }
public System.DateTime Created { get; set; }
public string Title { get; set; }
}
In MVC3 I generate the FooController via the db context and foo model. When I bring up /Foo/Create and hit "Create" on the blank form it shows a validation error on "Created" field but not on "Title".
If I enter only a "created" date I get an exception:
Validation failed for one or more entities. See 'EntityValidationErrors'
property for more details
The exception is "The Title field is required".
I'm not sure why it works fine for one column but not the other. My first fix was to simply add the annotation, however the class code is auto generated by EF.
The only fix that seems to work is to use a partial metadata class: ASP.NET MVC3 - Data Annotations with EF Database First (ObjectConext, DbContext)
I can add the [Required] tag as desired however this should be unnecessary. Is this a bug in EF or am I just missing something?
This isn't a bug, EF simply doesn't add those attributes. As far as i know, the database-first approach (Entity classes generated by the designer) doesn't even perform the validation. The link you're refering to is a valid solution for your problem. The principle of buddy-classes which contain the actual metadata was introduced due to the fact, that you cannot add attributes to existing properties in a partial class.
The code-first approach has a built-in functionality to validate your annotations, see: Entity Framework 4.1 Validation. Another solution when using database-first would be to create a custom code-generator that applies those attributes T4 Templates and the Entity Framework.