Entity layout contains int value of venue (VenueId prop), its own id and other information.
CONSTRAINT [FK_Venue_Layout] FOREIGN KEY ([VenueId]) REFERENCES [dbo].[Venue] ([Id])
When I trying to add two layouts with the same VenueId, I'm getting this error
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: Saving or accepting changes failed because more than one entity of type 'DataAccess.Models.LayoutModel' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration."
My entity code:
[Table("Layout")]
public class LayoutModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int VenueId { get; set; }
public string Description { get; set; }
}
Insertion code:
var layouts = new List<LayoutModel>
{
new LayoutModel { VenueId = 1, Description = "First layout" },
new LayoutModel { VenueId = 1, Description = "Second layout" },
};
_context.Layouts.AddRange(layouts);
_context.SaveChanges();
I'm not allowed to use navigation properties
Id column or property is marked as identity column in the definition of LayoutViewModel
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
So, no need to assign it explicitly as it will be populated by Database automatically after the row is inserted into Layout table. Please update your layouts population as below to remove Id assignment:
var layouts = new List<LayoutModel> {
new LayoutModel { /*Id = 1,*/ VenueId = 1, Description = "First layout" },
new LayoutModel { /*Id = 2, */ VenueId = 1, Description = "Second layout" }
};
// code smell
foreach(var layout in layouts)
{
context.Entry(layout).State = EntityState.Added;
}
_context.Layouts.AddRange(layouts);
_context.SaveChanges();
Also, please update your LayoutModel as below:
public class LayoutModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Column(Order = 0)]
public int Id { get; set; }
[Key]
[Column(Order = 1)]
//[ForeignKey("Venue")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int VenueId { get; set; }
//public virtual VenueModel Venue { get; set; } //Please correct Venue property type
}
Also, please verify whether Venue is loaded into _context.Layouts or not.
Related
I have the following model class:
public partial class ORD_Garanzie
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ID { get; set; }
[Column(Order = 1)]
[Key]
public int intestatario { get; set; }
[Column(Order = 2)]
[Key]
public string n_polizza { get; set; }
........other properties
}
The method that is adding entries in the DB is as follows:
public ORD_Garanzie[] SaveORD_Garanzie(ORD_Garanzie[] ordGaranzieItems)
{
using (TBSContext context = new TBSContext())
{
if (ordGaranzieItems.Length != 0 || ordGaranzieItems != null)
{
try
{
foreach (var garanzieItem in ordGaranzieItems)
{
context.Entry(garanzieItem).State = garanzieItem.ID == 0 ?
EntityState.Added :
EntityState.Modified;
}
context.SaveChanges();
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
throw;
}
return ordGaranzieItems;
}
return null;
}
}
The problem is that if I'm updating the value of one of the properties marked with the [Key] attribute I'm receiving the following error when SaveChanges() is called: System.Data.Entity.Infrastructure.DbUpdateConcurrencyException:
'Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
If I am updating any of the other properties that are NOT marked with the KEY attribute in the model class OR adding a new entity completely, I receive no error.
Or if I remove the KEY attributes (and Column attribute) from the model class, the problem goes away.
Any idea how to solve this? Or a better solution to UPDATE or ADD an array of entities when I have this CONSTRAINT that the two properties must be unique. (I also need to be able to change them if need be).
In order to have your ID as key, remove the Key annotations from the other columns. To enforce a unique combination of the other columns, use the Index(name, order, IsUnique=true) annotation:
public partial class ORD_Garanzie
{
public long ID { get; set; }
[Column(Order = 1)] // optional, not needed for the index
[Index("IX_SomeIndexName_Unique", 0, IsUnique = true)]
public int intestatario { get; set; }
[Column(Order = 2)] // optional, not needed for the index
[Index("IX_SomeIndexName_Unique", 1, IsUnique = true)]
public string n_polizza { get; set; }
I am trying to write to two tables in my database in a function that takes in lists as a parameter from the previous page. I call the db to retrieve the purchase_order_no because the column is an IDENTITY primary key that is generated on entry.
Models:
purchase_order
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int client_no { get; set; }
[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int purchase_order_no { get; set; }
[StringLength(60)]
public string name { get; set; }
[Key]
[Column(Order = 2)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int order_group_no { get; set; }
[StringLength(24)]
public string purchase_order_reference { get; set; }
[Key]
[Column(Order = 3)]
public DateTime order_timestamp { get; set; }
order_detail
[Key]
[Column(Order = 0)]
public long order_detail_no { get; set; }
[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int purchase_order_no { get; set; }
[Key]
[Column(Order = 2)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int inventory_no { get; set; }
[Key]
[Column(Order = 3)]
public decimal quantity { get; set; }
public int? vendor_no { get; set; }
I receive this error when trying to insert my new 'purchase_order' model into the db:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
[HttpPost]
public ActionResult orderForm (List<int> quantity, List<string> itemName, List<int> inventory_no, List<int> client_no, List<int> vendorCode, int orderGroupNo)
{
using (var db = new db_model())
{
var ctx = ((IObjectContextAdapter)db).ObjectContext;
purchaseOrderVM poVM = new purchaseOrderVM();
List<order_detail> tempList = new List<order_detail>();
purchase_order po = new purchase_order();
po.client_no = client_no[0];
var purchaseOrder = db.purchase_order.Where(x => x.client_no == po.client_no).Max(x => x.purchase_order_no);
po.order_group_no = orderGroupNo;
po.order_timestamp = DateTime.Now;
db.purchase_order.Add(po);
try
{
db.SaveChanges(); <!-- This is where I get the error -->
}
catch (OptimisticConcurrencyException e)
{
ctx.Refresh(RefreshMode.ClientWins, db.purchase_order);
throw e;
}
for (int i = 0; i < itemName.Count(); i++)
{
order_detail od = new order_detail();
od.purchase_order_no = db.purchase_order.Where(x => x.client_no == po.client_no).Max(x => x.purchase_order_no);
od.inventory_no = inventory_no[i];
od.quantity = quantity[i];
od.vendor_no = vendorCode[i];
db.order_detail.Add(od);
try
{
db.SaveChanges();
}
catch (OptimisticConcurrencyException e)
{
ctx.Refresh(RefreshMode.ClientWins, db.order_detail);
throw e;
}
tempList.Add(od);
}
poVM.purchase_order = po;
poVM.orderList = tempList;
return View(poVM);
}
}
I think the problem is in your model class. In purchase_order, why do you have so many columns flagged as [Key]? As purchase_order_no is declared as an identity column, it should be the primary key by itself. I don't even know why EF doesn't complain at startup, because your configuration makes no sense.
Remove the [Key] attribute on all other columns, and it should work. If you need to ensure uniqueness, you can create a unique index on the other columns.
I will not question your model as to why you have so many columns flagged as [Key] in the first place. That's not helping you with your problem. Moreover, you might want all those columns in your primary key for performance reasons: when using code first with EF, the primary key is created as clustered by default.
The problem is probably not the number of columns with attribute [Key]. I had the same problem after incorporating just one extra column of type DateTime in the primary key, and you also have a DateTime column in your primary key combination for entity purchase_order.
It looks like EF is not handling DateTime columns very well, when marked as part of the primary key. I found an interesting webpage that confirms this: https://social.msdn.microsoft.com/Forums/en-US/6f545446-aa26-4a21-83e9-60f7fa5ed3b0/optimisticconcurrencyexception-when-trying-to-insert-a-new-record-in-table-using-entity-framework?forum=adodotnetentityframework
I can think of two solutions for your problem:
If you want to stick with your primary key definition: truncate your [order_timestamp] to a value your database does accept. In case of SQL Server you'll be doing fine when truncating to 10 msec, C#:
order_timestamp = DateTime.Now.Truncate(TimeSpan.FromMilliseconds(10));
If you don't want to truncate your timestamp but accept to change your PK combination to an index: consider adding an autonumber column for the primary key:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
and changing the other key attributes to:
[Index("IX_purchase_order", Order = 1)],
[Index("IX_purchase_order", Order = 2)], etc.
For performance, you might want the index to be created as clustered:
[Index("IX_purchase_order", IsClustered = true, Order = 1)], etc.
But when using Migrations, bear in mind that unfortunately EF will still try to create your PK as clustered as well. This would give errors when issuing command update-database, you first will have to change your migration code a little. Although in the code you will find something like:
.Index(t => new{client_no, ..., order_timestamp}, clustered: true, name: "IX_purchase_order")
you explicitly must declare the primary key non-clustered, by changing the migration code for the PK part to:
.PrimaryKey(t => t.Id, clustered: false)
I hope this helps.
Sorry for my bad English.
I have EF 6 codefirst models for database.
3 models is usually static, loaded at program startup (using aka foreign keys for last table).
Last model is dynamical - data is loaded too, stored in c# collection, but user can add, edit rows and save added/edited to DB.
For 3 first models i have checkboxes with selecteditem binding.
User can edit last table model entity, select items from checkboxes and save to DB.
This is simple and standart solution.
Partial models without trash fields (to reference from last table).
[Table("Users")]
public partial class User
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClientId { get; set; }
[StringLength(160)]
public string ClientName { get; set; }
public virtual ICollection<Repair> Repairs { get; set; }
public User()
{
Repairs = new List<Repair>();
}
}
[Table("RepairStatuses")]
public partial class RepairStatus
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(10)]
public string Status { get; set; }
public virtual ICollection<Repair> Repairs { get; set; }
public RepairStatus()
{
Repairs = new List<Repair>();
}
}
[Table("CurrentStatuses")]
public partial class CurrentStatus
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int StatusId { get; set; }
[StringLength(10)]
public string Status { get; set; }
public virtual ICollection<Repair> Repairs { get; set; }
public CurrentStatus()
{
Repairs = new List<Repair>();
}
}
And main editable table model (partial too w/o trash fields).
[Table("Repairs")]
public partial class Repair
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Column(TypeName = "date")]
public DateTime Date { get; set; }
[StringLength(255)]
public string HardwareInfo { get; set; }
public virtual User User { get; set; }
public virtual RepairStatus RepairStatus { get; set; }
public virtual CurrentStatus CurrentStatus { get; set; }
}
In my AddEntity method all working (attach unchanged items from combobox to DbContext, add new row, save changes). Eager loading.
using (ServiceDBContext cntx = new ServiceDBContext())
{
cntx.Users.Attach(SelectedRepair.User);
cntx.CurrentStatuses.Attach(SelectedRepair.CurrentStatus);
cntx.RepairStatuses.Attach(SelectedRepair.RepairStatus);
cntx.Entry(SelectedRepair.RepairStatus).State = EntityState.Modified;
cntx.Entry(SelectedRepair.CurrentStatus).State = EntityState.Modified;
cntx.Entry(SelectedRepair.User).State = EntityState.Modified;
cntx.Repairs.Attach(SelectedRepair);
cntx.Entry(SelectedRepair).State = EntityState.Added;
...
cntx.SaveChanges();
...
But with EditEntity method i have strange behavior (sorry for stupid code...)
using (ServiceDBContext wrk = new ServiceDBContext())
{
var tmp = (((((wrk.Repairs.Where(x => x.Id ==SelectedRepair.Id)).Include(y => y.CurrentStatus)).Include(y => y.RepairStatus)).Include(y => y.Engineer)).Include(y => y.User)).FirstOrDefault();
if (tmp.User.ClientId != SelectedRepair.User.ClientId)
{
tmp.User = SelectedRepair.User;
wrk.Users.Attach(tmp.User);
wrk.Entry(tmp.User).State = EntityState.Modified;
}
if (tmp.RepairStatus.Id != SelectedRepair.RepairStatus.Id)
{
tmp.RepairStatus = SelectedRepair.RepairStatus;
wrk.RepairStatuses.Attach(tmp.RepairStatus);
wrk.Entry(tmp.RepairStatus).State = EntityState.Modified;
}
if (tmp.CurrentStatus.StatusId != SelectedRepair.CurrentStatus.StatusId)
{
tmp.CurrentStatus = SelectedRepair.CurrentStatus;
wrk.CurrentStatuses.Attach(tmp.CurrentStatus);
wrk.Entry(tmp.CurrentStatus).State = EntityState.Modified;
}
...
wrk.Entry(tmp).State = EntityState.Modified;
wrk.SaveChanges();
}
For example: CurrentStatuses table have 2 entities ("1. OK", "2. Bad").
Then user first time changing in Repair table in selected row CurrentStatus foreign key (for example, with id =1 to foreign key with id=2) all is OK.
In VS debugger i can see...
UPDATE [dbo].[CurrentStatuses] SET [Status] = #0 WHERE ([StatusId] = #1)
UPDATE [dbo].[Repairs] SET ... WHERE (([Id] = #12) AND ([CurrentStatus_StatusId] = #13))
If user want to change second time this entity from id=2 to id=1 (reverse) its throwing error "An error occurred while saving entities that do not expose foreign key properties for their relationships..."
AND in debugger we can see some magic with "Reader (INSERT)" attempts to all database relative tables o_O and attempt to INSERT in Repair table dublicate entry (which was been selected to edit).
One INSERT example (Repair, RepairStatus and User have like this INSERTS too):
DECLARE #0 AS SQL_VARIANT;
SET #0 = NULL;
INSERT [dbo].[CurrentStatuses]([Status])
VALUES (#0)
SELECT [StatusId]
FROM [dbo].[CurrentStatuses]
WHERE ##ROWCOUNT > 0 AND [StatusId] = scope_identity()
After program restart we can change CurrentStatus foreign key from id=2 to id=1 normally (but only 1 time too).
Can someone help me to solve this problem?
Thanks!
I have two table
Product and Order
public class Product
{
string name;
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid productId { get; set; } // i want this to be primary key instead default Id
}
public class Order
{
string name;
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid orderId { get; set; } // i want this to be primary key instead default Id and also want to add productId inside this table as foreign key
}
I have used following code to use code first.
DatabaseContext.cs
class DatabaseContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Order> Orders { get; set; }
}
Program.cs
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<DatabaseContext>());
using (var context = new DatabaseContext())
{
context.Product.Add(new Product() { Name = "mytest" });
context.SaveChanges();
}
Console.WriteLine("Database Created!!!");
Console.ReadKey();
}
getting exception
Additional information: Unable to determine composite primary key ordering for type '.Customer'. Use the ColumnAttribute (see http://go.microsoft.com/fwlink/?LinkId=386388) or the HasKey method (see http://go.microsoft.com/fwlink/?LinkId=386387) to specify an order for composite primary keys.
EF supports only properties so you should change your fields to properties. When you do that use {class Name} + Id as the property name and it will be picked up as the key property by convention. Alternatively you can use the [Key] attribute on a property to let EF know it should be the key property. You can find more about EF attributes here.
I'm trying to do something simple, but this dont work in EF 4.1,it does in EF 6, but I cant update version because I need this application in an old server and doesnt support it.
This is my code:
chat = new Chat()
{
AdminId = 99
};
db.Chat.Add(chat);
db.SaveChanges();
var cp = new List<ChatPeople>();
foreach (int user in usersids)
{
cp.Add(new ChatPeople
{
ChatId = chat.Id,
UserId = user
});
}
cp.ForEach(c => db.ChatPeople.Add(c));
and this is the model:
[Table("CHATS", Schema = "SCHEMA")]
public class Chat
{
[Column("ID")]
public decimal Id { get; set; }
[Column("ADMINID")]
public decimal AdminId { get; set; }
public virtual ICollection<ChatPeople> ChatPeople { get; set; }
public virtual ICollection<ChatHistory> ChatHistory { get; set; }
}
(I need decimal Id because int dont work in Oracle.)
My problem is when I save Chat, this dont return the current Id of this registry in database and when in ChatPeople try to do this ChatId = chat.Id, I dont have the value. In DB Chat are saving ok with AdminId = 99 and Id = (Autonumeric-Identity)
What can I do to get Id of registry that are being saved?
Try adding the attribute [Key] above your ID This should set it as the primary key for the table that's generated by EF.
[Key]
[Column("ID")]
public decimal Id { get; set; }
I need put this other attribute [DatabaseGenerated(DatabaseGeneratedOption.Identity)] and works ok.
Answer in this post:
Entity Framework Code First Using One column as Primary Key and another as Auto Increment Column
Finally:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("ID")]
public decimal Id { get; set; }