Ive got an existing table with a column thats a Guid which I added after a while so there is records in the table before which have a 00000000-0000-0000-0000-000000000000 value.
Now I want to add a FK in entity framework since this guid references another tables ID, but when I change the model from: Guid OtherDtoId -> myDto otherDtoId I run into the error: The ALTER TABLE statement conflicted with the FOREIGN KEY constraint.
Im aware that this error is due to the existing empty Guids doesnt have a corresponding guid in the other table. I thought I would get around this by setting the Guid OtherDtoId to nullable so that the 0000... ones wouldnt matter, but it doesnt seemt to solve it.
Is there a way to keep my records in the table and add a FK that is nullable? EF wanted to drop the column completely but that isnt possible since there is existing records present..
public class OriginalDto
{
public Guid ID { get; set; }
public Guid OtherDtoId { get; set; } // I want to change this to public myDto otherDtoId { get; set; }
}
Because OtherDtoId afte alter will be a FK and could not empty, so 00000000-0000-0000-0000-000000000000 could not be valid. You should deletes those 0000... records or update OtherDtoId to not-empty value before update database.
Related
I defined a class (as the model for EF), but when I ran migrations to update the DB schema I got this error:
The entity type 'xyz' requires a primary key to be defined.
Sure, it's easy enought fix to add:
public int Id { get; set; }
From a domain model point of view I do not need a primary key on this entity. It is a dependent entity with one-many relationship and doesn't need to be unique.
So, this is more of a curiousity (than a serious problem) but is there a way not to define a primary key?
We've started using EF6 as part of rewriting our application suite. There are many perfectly reasonable tables in the existing suite and we're reusing them using a database-first approach. My problem is that EF6 seems to be enforcing what I think are code-first conventions on my database-first model.
Consider this minimal example with two tables defined thusly and appropriately populated with a few rows:
CREATE TABLE [dbo].[Table1] (
[Id] INT NOT NULL PRIMARY KEY,
[Table2Reference] INT NOT NULL REFERENCES [dbo].[Table2](Id) )
CREATE TABLE [dbo].[Table2] (
[Id] INT NOT NULL PRIMARY KEY,
[SomeColumn] NVARCHAR(25) )
After running Update Model From Database we get this model:
(Oops. Not enough reputation to post images. It's what you would imagine.)
So far so good, but when you write code to access the Table1 entity, like so...
var q = _context.Table1.ToList();
foreach (var item in q)
Debug.WriteLine("{0}", item.Table2Reference);
... it compiles fine but will throw on the ToList() line. This is because the SQL generated contains a request for a column that doesn't even exist:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Table2Reference] AS [Table2Reference],
[Extent1].[Table2_Id] AS [Table2_Id] <-- this one doesn't exist
FROM [dbo].[Table1] AS [Extent1]
I gather this has something to do with a code-first naming convention for foreign keys. I know I can rename Table2's Id column to Table2Id and rename Table2Reference to Table2Id and it will work. However, this is supposed to be database-first. Is there some way to tell EF to get out of the way and just go with what is actually in the pre-defined database? I did discover early on that I had to turn off the name pluralizing convention, but I can't seem to identify a convention to turn off that fixes this problem. I tried removing these:
modelBuilder.Conventions.Remove<PrimaryKeyNameForeignKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<TypeNameForeignKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<NavigationPropertyNameForeignKeyDiscoveryConvention>();
Anyway, I'm stumped. Is there an easy workaround that doesn't involve modifying the existing database?
Thanks for reading.
You can use data annotations attributes or fluent API to configure EF mapping to actual database tables. Here is how it can be done with attributes:
[Table("Table1")]
public class Table1
{
public int Id { get; set; }
public int Table2Reference { get; set; }
[ForeignKey("Table2Reference")]
public Table2 Table2 { get; set; }
}
It turns out that there is a very important piece to a database-first approach besides having an EDMX file. That is, your connection string must contain the following section:
metadata=res:///IPE.csdl|res:///IPE.ssdl|res://*/IPE.msl; (replacing IPE with the base name of your EDMX)
Otherwise, EF will be unable to locate the EDMX information in the assembly and code-first conventions can come into play. Mostly things just work, until they don't.
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 to create an entity framework model for a badly designed database. The database uses table per type inheritance but it does so with using a PK->FK relationship, not a PK->PK relationship. E.g.
Person
PersonID (PK)
Name
Employee
EmployeeID (PK)
PersonID (FK)
DateStarted
HourlyEmployee
HourlyEmployeeID (PK)
EmployeeID (FK)
HourlyRate
Obviously this is just badly designed, but I can't change it. Table per type inheritance in the entity framework essentially wants EmployeeID not to exist and the PK for Employee to be PersonID. Is it possible to create a model for this database, or do I choose another tool? any recommendations?
You will not map this as TPT inheritance because your database is configured in the way that doesn't allow you cheating EF.
If Employee.EmployeeID is auto-generated in the database and Employee.PersonID is unique (uniqueness must be enforced in the database) you should be able (not tested) to cheat EF by simply mapping:
public Employee : Person {
public DateTime DateStarted { get; set; }
}
This class will tell EF that Employee inherits key from Person (PersonID) and you will hide the real key from EF - this should work if the real key is auto-generated.
The problem is your next level of inheritance which breaks this pattern. To make this work your HourlyEmployee will have to reference PersonID - not EmployeeID. EF now doesn't know about EmployeeID existence so it even cannot map relation with HourlyEmployee.
TPT inheritance in code first has one additional limitation - PK column must have the same name in all tables.
You can create a model from the database if it exists but it might not be what you expect. EF sometimes doesn't work that great with weird database structures.
I have a simple table with an ID (a uniqueidentifier), a datetime, and a value.
I'd like to use getdate() on the database for the record insertion time and newid() for the id. How do I configure entity framework to do this? When I try to assign the id on the DB I get:
Violation of PRIMARY KEY constraint 'PK_Random'. Cannot insert duplicate key in object 'dbo.Random'. The duplicate key value is (00000000-0000-0000-0000-000000000000).
if you are using code first. Please add the following to your guid.
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid guId { get; set; }
This will enable sql server side guid generation. Hope it helps.
Just to add to this since #lunateck answer helped me. The other way (if you are using Database First) is to:
Open your edmx file.
Right click -> Model Browser
Right click the Guid column -> Properties -> change the StoreGeneratedPattern to Identity.