I am using code first migrations with an existing database. I used the reverse engineering feature to generate all the initial entities. However, the database was not well designed and one of the tables did not have a primary key designated. Apparently Entity Framework did its best to infer the primary key and didn't get it right. It looks like it decided to make two fields a compound primary key.
I want to actually remove one of the fields that it mistakenly thinks is part of the primary key and it's resulting in errors.
Here is the original schema of the table when the entity was created for it:
CREATE TABLE [dbo].[Table1](
[The_ID] [bigint] IDENTITY(1,1) NOT NULL,
[Field_1] [varbinary](max) NULL,
[Field_2] [bigint] NULL,
[Field_3] [varbinary](max) NULL,
[Field_4] [datetime] NULL,
[Field_5] [bit] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table1] ADD CONSTRAINT [DF_Table1_F5] DEFAULT ((0)) FOR [Field_5]
GO
The_ID should have been designated as the primary key but as you can see it was not. Here is class the Visual Studio generated:
public partial class Table1
{
[Key]
[Column(Order = 0)]
public long The_ID { get; set; }
public byte[] Field_1 { get; set; }
public long? Field_2 { get; set; }
public byte[] Field_3 { get; set; }
public DateTime? Field_4 { get; set; }
[Key]
[Column(Order = 1)]
public bool Field_5 { get; set; }
}
It apparently decided to make The_ID and Field_5 into a compound primary key. At least that's how I'm interpreting this code. Now, I actually need to remove Field_5 from the table. I created an migration to do this, but since Entity Framework thinks its part of a primary key its doing weird things like dropping the primary key and re-adding it, which is resulting in errors. Here is the generated migration code:
public override void Up()
{
DropPrimaryKey("dbo.Table1");
AlterColumn("dbo.Table1", "The_ID", c => c.Long(nullable: false, identity: true));
AddPrimaryKey("dbo.Table1", "The_ID");
DropColumn("dbo.Table1", "Field_5");
}
Running this results in the following error:
ALTER TABLE [dbo].[Table1] DROP CONSTRAINT [PK_dbo.Table1]
System.Data.SqlClient.SqlException (0x80131904): 'PK_dbo.Table1' is not a constraint.
So how do I get myself out of this mess?
I tried removing the [Key] attributes from The_ID and Field_5 and creating a dummy migration using
Add-Migration dummy -IgnoreChanges
with the thought that I could then add the [Key] attribute back to The_ID and remove Field_5 but it won't let me create a migration unless at least one field is designated with the [Key] attribute. But if I do that to get the dummy migration in place then I can't do it in a real migration so I'm not able to actually designate The_ID as the primary key using code first migrations.
Any ideas?
If you have a Table without Primary Key in you Database EntityFramework will interpret every not nullable column in the table as part of the Primary Key.
In this case you could just remove the first two lines from the generated Migration, because there is no primary key to drop. EntityFramework just does not know about this fact.
public override void Up()
{
//DropPrimaryKey("dbo.Table1");
//AlterColumn("dbo.Table1", "The_ID", c => c.Long(nullable: false, identity: true));
AddPrimaryKey("dbo.Table1", "The_ID");
DropColumn("dbo.Table1", "Field_5");
}
Related
I create a table with primary key.
I tried to insert new data with entityframework6, but it would get 23502 error.
But I add the default value to the column before I insert it.
I don't understand why it would get this error.
Table DDL:
CREATE TABLE ERRORLOG(
id numeric NOT NULL,
message varchar(50) NULL,
CONSTRAINT pterrorlog_pk PRIMARY KEY (id)
);
Model:
public partial class ERRORLOG
{
[Key]
[Column(Order = 0)]
public long ID { get; set; } = DateTimeOffset.Now.ToUnixTimeMilliseconds();
public string MESSAGE { get; set; }
}
Funcation:
using (DbContext Db as new DbContext)
using (TransactionScope transactionScope = new TransactionScope())
{
ERRORLOG iLog = new ERRORLOG();
iLog.MESSAGE = Message;
Db.ERRORLOG.Add(iLog);
Db.SaveChanges(); //Get 23502 error
}
Here is the insert script, it looks like didn't insert the id, why is that?
INSERT INTO "pterrorlog"("message") VALUES (#p_0) RETURNING "id"
Edit:
After I add this script on the Model, it works fine now.
public partial class ERRORLOG
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long ID { get; set; } = DateTimeOffset.Now.ToUnixTimeMilliseconds();
public string MESSAGE { get; set; }
}
Looks like Entity Framework auto insert a value to the column.
After I add the script to prevent this issue, it works fine now.
[DatabaseGenerated(DatabaseGeneratedOption.None)]
Model would like:
public partial class ERRORLOG
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long ID { get; set; } = DateTimeOffset.Now.ToUnixTimeMilliseconds();
public string MESSAGE { get; set; }
}
You can use PGAdmin to profile the SQL that EF is actually attempting to execute on SaveChanges. C# is case sensitive while Postgres defaults to lower case. If I recall NPGSQL will format all EF SQL Queries with double-quotes so if your Entities were declared with properties like ID, it would be generating statements like INSERT INTO "ERRORLOG" ( "ID", "MESSAGE" ) VALUES ( ... ) so a column named "id" wouldn't be getting set.
If you want your entities to use a different case than the DB, and leave Postgres using lower case then I'd recommend using [Column] attributes to rename the columns:
public partial class ERRORLOG
{
[Key, Column(Name = "id")]
public long ID { get; set; } = DateTimeOffset.Now.ToUnixTimeMilliseconds();
[Column(Name = "message")]
public string MESSAGE { get; set; }
}
The other detail is that Order on the Column attribute is only needed when dealing with composite keys, such as many-to-many joining tables where the PK is made up of two or more columns. It isn't needed for normal single-value PKs.
If that isn't the cause, checking the insert statement in PGAdmin should give you a clue what NPGSQL / EF is attempting to execute.
I have an entity type MyEntity that has a primary key string MyEntityCode
I want to make a second entity MyEntityInfo that are extended properties that some MyEntity's are logically associated.
That makes the relationship between these entities one-to-one, with one end optional -- MyEntity logically optionally has a MyEntityInfo, without a navigation property, and MyEntityInfo is required to have a single MyEntity (with a navigation property).
I want to encode this in SQL as MyEntityInfo having a primary key BaseEntityCode that's also a foreign key to MyEntity's MyEntityCode.
How do I configure this encoding in EF6 fluent configuration API.
Sample code
public class MyEntity {
public string MyEntityCode {get; set;}
public int SomeProperty {get; set;}
}
public class MyEntityInfo {
public MyEntity BaseEntity {get; set;}
public string BaseEntityCode {get; set;}
public int OtherInfo {get; set;}
}
public MyEntityConfiguration : EntityConfiguration<MyEntity> {
public MyEntityConfiguration(){
HasKey(e => e.MyEntityCode);
}
}
I thought I could configure MyEntityInfo as
public MyEntityInfoConfiguration : EntityConfiguration<MyEntityInfo> {
public MyEntityInfoConfiguration(){
HasKey(e => e.BaseEntityCode);
HasRequired(e => e.BaseEntity).WithOptional().WithForeignKey(e => BaseEntityCode);
}
}
but WithOptional() doesn't allow chaining to WithForeignKey
Doing the same but with WithMany() so that a foreign key is possible, the multiplicity constraint of one is violated:
Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
I thought I could configure MyEntityInfo as
public class MyEntityInfoConfiguration : EntityTypeConfiguration<MyEntityInfo>
{
public MyEntityInfoConfiguration(){
HasKey(e => e.BaseEntityCode);
HasRequired(e => e.BaseEntity).WithOptional().WithForeignKey(e => BaseEntityCode);
}
}
Well, almost, just remove the WithForeignKey call!
public class MyEntityInfoConfiguration : EntityTypeConfiguration<MyEntityInfo>
{
public MyEntityInfoConfiguration()
{
HasKey(e => e.BaseEntityCode);
HasRequired(e => e.BaseEntity).WithOptional();
}
}
Entity Framework 6 has only one implementation of 1:1 associations: the primary key of the dependent entity (here: MyEntityInfo) is the foreign key to the principal entity (here: MyEntity).
There is no WithForeignKey method because with your proposed mapping (without WithForeignKey) EF knows all it needs to know now for the only implementation of 1:1 it has in store.
The produced database model shows the primary key/foreign key dual role of BaseEntityCode:
CREATE TABLE [dbo].[MyEntities] (
[MyEntityCode] [nvarchar](128) NOT NULL,
[SomeProperty] [int] NOT NULL,
CONSTRAINT [PK_dbo.MyEntities] PRIMARY KEY ([MyEntityCode])
)
CREATE TABLE [dbo].[MyEntityInfoes] (
[BaseEntityCode] [nvarchar](128) NOT NULL,
[OtherInfo] [int] NOT NULL,
CONSTRAINT [PK_dbo.MyEntityInfoes] PRIMARY KEY ([BaseEntityCode])
)
...
ALTER TABLE [dbo].[MyEntityInfoes]
ADD CONSTRAINT [FK_dbo.MyEntityInfoes_dbo.MyEntities_BaseEntityCode]
FOREIGN KEY ([BaseEntityCode]) REFERENCES [dbo].[MyEntities] ([MyEntityCode])
Using Entity Framework Code First, I'm seeing very strange behavior when inserting a row with a composite key. The composite key consists of a guid ID field and a guid foreign key field, creating an "identifying relationship". The strange behavior is that regardless of what I set the ID and foreign key field to, the generated SQL sets them both to the foreign key value.
My classes look like this:
public class Parent {
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child {
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public Guid ParentId { get; set; }
}
In my DbContext file I have:
modelBuilder.Entity<Child>().HasKey(c => new { c.Id, c.ParentId });
Doing something like:
var parent = new Parent() { Id = Guid.NewGuid() };
var child = new Child() { Id = Guid.NewGuid(), ParentId = parent.Id };
parent.Children.Add(child);
You'd think the SQL executed would insert a new child with differing Id and ParentId values. But instead, what I'm seeing is:
// Assume parent is already in the DB, with ID of '1b1a6ecd-00ad-4265-ac0d-9a50bd30e247'
INSERT [dbo].[Child]
([Id],
[ParentId])
VALUES ('1b1a6ecd-00ad-4265-ac0d-9a50bd30e247' /* #0 */,
'1b1a6ecd-00ad-4265-ac0d-9a50bd30e247' /* #1 */)
Why is the SQL using the ParentId value for both fields? This doesn't make sense at all.
UPDATE
Unless I totally misunderstand something fundamental to EF, I think this must be a bug. I've uploaded a tiny reproducible project to http://1drv.ms/1kX2oVC
It uses EF 6.1 and .NET 4.5. I'm hoping some EF expert can chime in here and confirm this is a bug, or that I'm doing something fundamentally wrong.
With this set up Entity Framework isn't able to properly infer the associations. You have two options how to fix it:
Add modelBuilder.Entity<Parent>().HasMany(x => x.Children).WithRequired().HasForeignKey(x => x.ParentId); into your OnModelCreating.
or
Add public Parent Parent { get; set; } into your Child entity.
First of all, I'm new to Entity Framework and I'm trying to do a project using the Code-First model, so please forgive my ignorance on what may turn out to be a trivial problem...
I'm working on creating some POCO EF classes and I'm having difficulty figuring out how to setup some of the relationships in the DbContext derived class.
If I were to setup the tables with SQL, this is what they would look like (extraneous columns removed for clarity and brevity:
CREATE TABLE DBO.Application (
ApplicationId NUMERIC(18,0) IDENTITY(1,1) NOT NULL,
MinimumVersionId NUMERIC(18,0),
CurrentVersionId NUMERIC(18,0));
CREATE TABLE DBO.ApplicationVersion (
ApplicationVersionId NUMERIC(18,0) IDENTITY(1,1) NOT NULL,
ApplicationId NUMERIC(18,0) NOT NULL;
ALTER TABLE DBO.Application ADD
PRIMARY KEY (ApplicationId),
CONSTRAINT Application_FK1
FOREIGN KEY (MinimumVersionId)
REFERENCES DBO.ApplicationVersion (ApplicationVersionId),
CONSTRAINT Application_FK2
FOREIGN KEY (CurrentVersionId)
REFERENCES DBO.ApplicationVersion (ApplicationVersionId);
ALTER TABLE DBO.ApplicationVersion ADD
PRIMARY KEY (ApplicationVersionId),
CONSTRAINT ApplicationVersion_FK1
FOREIGN KEY (ApplicationId)
REFERENCES DBO.Application (ApplicationId);
The relevant part of the ApplicationModel POCO class is (Application DB Table shown above):
public class ApplicationModel
{
public long ApplicationId { get; set; }
public virtual ApplicationVersionModel CurrentVersion { get; set; }
public long? CurrentVersionId { get; set; }
public virtual ApplicationVersionModel MinimumVersion { get; set; }
public long? MinimumVersionId { get; set; }
public virtual IList<ApplicationVersionModel> Versions { get; set; }
}
And the ApplicationVersionM POCO class (ApplicationVersion DB Table shown above):
public class ApplicationVersionModel
{
public virtual ApplicationModel Application { get; set; }
public long ApplicationId { get; set; }
public long ApplicationVersionId { get; set; }
}
So far, in the OnModelCreating method of the class that inherits from DbContext, I have this:
modelBuilder.Entity<ApplicationModel>()
.HasMany<ApplicationVersionModel>(a => a.Versions)
.WithRequired(av => av.Application)
.HasForeignKey(a => a.ApplicationId);
This is to establish the one to many relationship between Application and ApplicationVersion.
Where I'm getting confused is how to write the entries for the CurrentVersion and MinimumVersion fields. Each of these are to hold a value that would be found in ApplicationVersion.ApplicationVersionId (the primary key). However, these fields are nullable in the database and, therefore, optional.
I'm getting lost in all the options like:
WithMany - I know this one isn't it as I'm pointing to a single record
WithOptionalDependant
WithOptionalPrincipal
WithRequired - I don't think this is it since the field is nullable
And then, I'm not exactly sure what methods would be chained after that.
Any help would be appreciated. It would also be beneficial if, in your answers, you could explain WHY I need to do it that way. Knowing why will help me (and possibly others that may read the question) understand the processes and relationships better.
I am using EF4 and creating classes through the Entity design surface then generating the database from them. I want to add an attribute to some of the classes to show the timestamp they were last updated.
I have added a Version attribute to them, but I don't know which .Net datatype to associate with them so they become either Timestamp or RowVersion in the database when it is generated.
Any ideas?
You use byte[] type for rowversion/timestamp
Example use: http://www.ienablemuch.com/2011/07/using-checkbox-list-on-aspnet-mvc-with_16.html
If you are in the designer, just type in byte[] or System.Byte[], I think the field types dropdown selection on EF designer can be typed-in upon.
Given this DDL
create table Movie
(
MovieId int identity(1,1) not null primary key,
MovieName varchar(100) not null unique,
MovieDescription varchar(100) not null unique,
YearReleased int not null,
Version rowversion -- rowversion and timestamp are alias of each other
);
This is the class mapping:
public class Movie
{
[Key]
public virtual int MovieId { get; set; }
[ Required, Display(Name="Title")
] public virtual string MovieName { get; set; }
[ Required, Display(Name="Description")
] public virtual string MovieDescription { get; set; }
[ Required, Display(Name="Year Released"), Range(1900,9999)
] public virtual int? YearReleased { get; set; }
[Timestamp]
// byte[] is the rowversion/timestamp .NET type
public virtual byte[] Version { get; set; }
public virtual IList<Genre> Genres { get; set; }
}
As far as I know, rowversion is a relative binary value, not an actual time value. It increments for every insert and update that occurs. This allows you to compare values to determine which record is newer. Since it is relative, given a single rowversion value, you will know nothing, but given two rowversion values, you will know which is older and which is newer, but not by how much.
I don't know which .Net datatype to associate with them so they become either Timestamp or RowVersion in the database when it is generated.
I'm not sure, but most likely there isn't a datatype that will give you rowversion when going from model to database. You will have to change the database field type yourself, or add the field to the DB and bring the record up to your model. You could also generate the DDL and then modify it before creating the DB with it.
There is also another method where you can extend the functionality of the EF process by deriving from it's classes. You can then choose it yourself, but I'm not too familiar with how to do that.