I have got this weird error Cannot add an entity with a key that is already in use
But what is quite irritable about that error is that user gets no detais - Who? What? What table? What record is the culprit of this error?
It would be desperately complicated to determine it, in case you do many operations on LINQ objects before .Submit()
Is there any way to determine what certainly caused this error?
This error typically happens when you are creating a new record in a MetaTable with a foreign key relationship and the foreign key record already exists.
For example, let's say you have an Contact table and an Address table, and each Contact can hold multiple Addresses. The error occurs when you create a new Contact record and try to manually associate an existing Address record to that new Contact.
Assuming that the passed Address ID represents an existing Address record, this doesn't work:
public class Contact
{
public int Contact_ID { get; set; }
public string Name { get; set; }
public Address ContactAddress { get; set; }
public string Phone { get; set; }
}
public class Address
{
public int Address_ID { get; set; }
public string Street { get; set; }
public string CityState { get; set; }
public string ZIP { get; set; }
}
public void CreateNewContact(int addressID)
{
Contact contact = new Contact();
contact.Name = "Joe Blough";
contact.ContactAddress.Address_ID = addressID;
contact.Phone = "(555) 123-4567";
DataContact.SubmitChanges();
}
Historically, SQL developers are trained to just pass the ID value in order for the magic to happen. With LINQ-to-SQL, because the database activity is abstracted, we have to pass the whole object so that the LINQ engine can properly reflect the necessary changes in the ChangeSet. In the above example, the LINQ engine assumes that you are asking to create a new Address record, because it didn't have one to work with when the SubmitChanges was made and it has to respect the contract established by the foreign key relationship. It creates a blank Address record with the passed ID value. The error occurs because that ID value already exists in the data table and the ChangeSet has not flagged the Address delta as an Update.
The fix is to pass in the entire record, not just the ID value:
contact.ContactAddress = DataContext.Addresses.Where(a => a.Address_ID == addressID).Single();
Now, the LINQ engine can properly flag the incoming Address record as an existing one and not try to recreate it.
May be the column you trying to Attach(), Remove(), Add() or DeleteOnSubmit(), is a primary key and you are trying to add or attach the same value again.
Also you might be accessing a primary key or foreign key value column in a different method and it's not closed yet when you trying to call the above methods.
Above to these methods Attach(), Remove(), Add() or DeleteOnSubmit(), try to create a new instance of your datacontext again and run.
It sounds like you are doing an Table.Attach() and the entity you are attaching has a key value that L2S is already tracking. This has got nothing to do with a duplicate key in your physical database.
As explained on one of the answers above, this error is more likely due to trying to insert a record into the table with a repeated value on primary ID key field. You could solve the problem by selecting/creating a different primary key.
Related
I am working on an application where I am using .Net Core 2, EF Core and MySQL as database server via Code First approach.
I have 2 tables:
User
Employee
User table is the main table which contains the user information and Employee table is the child table which has a column ID_User as shown below:
public class User : BaseEntity
{
public int ID_User { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual ICollection<Employee> Employees{get;set;}
}
public class Employee : Entity
{
public int ID_Employee { get; set; }
public string Name { get; set; }
public int ID_User { get; set; }
public virtual User User { get; set; }
}
Everything works perfectly when I use the above mapping and I have enough data in both the tables.
Now, I want to make the column ID_User in Employee table as nullable
To implement this change I made following change to my model:
public class Employee : Entity
{
public int ID_Employee { get; set; }
public string Name { get; set; }
public int? ID_User { get; set; }
public virtual User User { get; set; }
}
and in mapping file:
builder.HasOne(x=>x.User).WithMany(y=>y.Employees).HasForeignKey(z=>z.ID_User).IsRequired(false);
After running the dotnet ef migrations add empuser command it generated the following migration code:
migrationBuilder.DropForeignKey(
name: "FK_Employee_User_ID_User",
table: "Employee");
migrationBuilder.AlterColumn<int>(
name: "ID_User",
table: "Employee",
nullable: true,
oldClrType: typeof(int));
migrationBuilder.AddForeignKey(
name: "FK_Employee_User_ID_User",
table: "Employee",
column: "ID_User",
principalTable: "User",
principalColumn: "ID_User",
onDelete: ReferentialAction.Restrict);
Now when I run dotnet ef database update it is giving me the following error:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'CONSTRAINT FK_Employee_User_ID_User' at line 1
Please help.
Thanks
Try putting the SQL statements directly into the MySQL Workbench.
Type "dotnet ef migrations script" in your commandprompt.
Copy the generated SQL script.
Paste it into your Workbench.
Check where the errors occur.
When I got similar errors using EF core 2 with MySQL this helped me understand the problem better and helped solve the problem. (for me it was a typing error). You can at least use this method to determine if it is an error in the migrations or in your SQL statements.
I know this is not a concrete solution, but I hope this will help you understand your problem and solve it :)
Have you checked foreign key name in database?
I have found bug from migration builder, where creating new table:
In my case I use EF Core 2.1 Mysql DotNet Connector bug
Where migration builder creates wrongly named foreign key name...
To avoid this wrongly named foreign key name:
fix for migration builder
If your foreign key is named wrongly, you can manually rename it in database and then your migration might work.
The key word CONSTRAINT is not supported for certain version of MYSQL . EF core generates drop constraint for dropping foreign key . I have to change the following:-
migrationBuilder.DropForeignKey(
name: "FK_XXXXX",
table: "XXXXXX");
to
migrationBuilder.Sql("ALTER TABLE XXXXXX DROP FOREIGN KEY FK_XXXXX");
I am using Entity Framework and have a connection to a MySQL database. The id column is set to use StoreGeneratedPattern Identity and the column in the database has been set to auto-increment. When I create a new object and save it to the database, the item posts correctly in the database. However, after saving, the id of the object in C# remains 0 rather than reflecting the value than was assigned by the database.
The section of code is given below:
Group newGroup = new Group("MyGroupName", "Active");
dbContext.Groups.Add(newGroup);
dbContext.SaveChanges();
int testId = newGroup.id;
Even though "newGroup" saves in the database with a database-assigned id, when I read the id (such as I do when reading testId) the id is still 0.
Based on this, I have tried adding
dbContext.Entry(newGroup).Reload();
after SaveChanges() and I have also tried (based on this and this) adding
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
objectContext.Refresh(System.Data.Objects.RefreshMode.StoreWins, newGroup);
after SaveChanges() in an attempt to refresh the object (and thus the id) from the database, yet the problem remains. How can I get the id that was assigned by the database?
EDIT: Adding class definition for Group:
[Table("groups")]
public partial class Group
{
public Group()
{
this.user_groups = new HashSet<UserGroup>();
}
public long id { get; set; }
public string name { get; set; }
public string status { get; set; }
public System.DateTime created_at { get; set; }
public System.DateTime updated_at { get; set; }
public virtual ICollection<UserGroup> user_groups { get; set; }
}
Try decorating your id with the [Key] attribute.
It SHOULD be this attribute
[DatabaseGenerated(DatabaseGenerationOption.Identity)]
However, this SHOULD be the default.
The [Key] attribute, should be unnecessary since the column name Id is magical... Although this might only be the case when using the accepted naming convention for C#.
I wonder if it might be the long that your id property is typed, or possibly the naming convention... you could try naming it Id.
I'm having the same problem with my project. What I did for a work around was to order the table (group) by the ID descending and select the first or default record, then select the ID column.
var newID = dbcontext.Groups.OrderByDescending(x => x.id).FirstOrDefault().ID
You can then assign that to whatever you need and save changes again. I know it's an old thread but hopefully this helps. Seems like there should be a better way to do it...
Consider the following database tables:
CREATE TABLE [dbo].[Step]
(
[StepId] INT NOT NULL PRIMARY KEY IDENTITY,
[OrderIndex] INT NOT NULL
)
CREATE TABLE [dbo].[StepInput]
(
[StepInputId] INT NOT NULL PRIMARY KEY IDENTITY,
[StepId] INT NOT NULL,
[OrderIndex] INT NOT NULL,
CONSTRAINT [FK_StepInput_Step] FOREIGN KEY ([StepId]) REFERENCES [Step]([StepId]) ON DELETE CASCADE,
)
With the following POCOs:
public class Step
{
public virtual int StepId { get; set; }
public virtual ICollection<StepInput> StepInputs { get; set; }
}
public class StepInput
{
public int StepInputId { get; set; }
public int StepId { get; set; }
public virtual int OrderIndex { get; set; }
}
I would like for StepInputs to be ordered by OrderIndex. Is there any way to setup the navigation property so that it is sorted automatically by EF, so that the user of Step does not have to call StepInputs.OrderBy every time?
I am using the database-first model.
Edit: I did realize that I could just add an OrderedInputs property to Step, which returns StepInputs.OrderBy(...), which solved the immediate problem, though I'm not sure about the performance implications. I am still curious as to whether there is a way to set this up in EF without having to use a custom property.
No way...! I think you have two tricks:
1) Create a static dbcontext, and for the first time, load the data you need into memory using .load() and perform your ordering, and then just use in-memory data in the Local property of your dbctx.<DbSet>s - an ugly way and most probably doesn't satisfy you...
2) Create a stored procedure to retrieve your data and perform ordering in database, and map that sp to an entity in your model.
I encountered a strange situation.
I have a root entity (table) with refereance to another entity (view)
public class RootEntity
{
public int Id {get; set;}
public int SubEntityId {get; set;}
public SubEntity SubEntity {get; set;}
}
public class SubEntity
{
public int Id {get; set;}
}
When I set only the RootEntity.SubEntityId with existing SubEntityId All goes well.
But, when I set the Ref to as follow
RootEntity.SubEntity = attachedSubEntity
For whatever reason EF is trying to insert the attached SubEntity to the view and I get this
System.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column '****', table '****'; column does not allow nulls. INSERT fails.
I found the problem! SubEntity was fetched with AsNoTracking option.
I thought that using this option will solve the "Insert" problem but in fact he was the cause!
When I removed the AsNoTracking addition all goes well.
It's still weird because the problem occurred only when used UnitTesting (Nunit). But with WCF I not encountered the problem
I have been playing around quite a lot with EF4 Code First and I do love it. However, I cannot seem to sort this easy one out.
When trying to create something like this, no columns are created in my database:
public IList<String> Recievers { get; set; }
public List<String> RecieversTest { get; set; }
public virtual List<String> RecieversAnotherTest { get; set; }
public virtual ICollection<Int32> RecieversAnotherTest { get; set; }
Ive tried Annotations to map it to a different column name, I've tried IEnumerable and all sorts of other collections, but it refuses to create a column for it.
After an hour on google I found one that claims she has done it, but I'm starting to doubt that. Should it even be possible?
I can't really see why it just doesn't create a column and use JSON or CSV.
It can't be that rare, can it? In my case i just want to store a list of emails.
What am I missing? The project creates all other types without problems, and I've inspected the database to see how other properties I add to test with gets created, while these gets ignored.
So the problem must lie in some setting I'm missing or some configuration....
EF 4.1 RTW on an SQL Server 2008 db.
I have bad news for you. EF doesn't do anything like that. If you want any serialization and deserialization you must do it yourselves = you must expose and map property with serialized value:
private IList<String> _receivers;
// This will be skipped
public IList<String> Receivers
{
get
{
return _receivers;
}
set
{
_receivers = value;
}
}
// This will be mapped
public string ReceiversSer
{
get
{
return String.Join(";", _receivers);
}
set
{
_receivers = value.Split(';').ToList();
}
}
Now ReceiversSer will be mapped to a column in the database.
You can't have a column based on a collection/list of something. A column is a singular item such as public string Receiver.
If you are expecting EF CF to take your IList or List and make several Columns out of it you are correct in that it won't.
In EF CF you create lists in your Entity to represent a relationship to another table. An Order may have many Items in it. You would in this case have an Order class with a list to an OrderItem object.
You would then have an OrderItem class to describe the OrderItem table. This would then essentially represent the 1 to many relationship of Order and OrderItems.