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.
Related
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.
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 have a model for orders. They both are keys and cannot be duplicated. I set OrderId as Identity in Map class.
class Order {
public int OrderId {get;set;}
public int OrderNumber {get;set;}
...
}
Now I need to generate new OrderNumber to insert the row. I know in SQL I can wrap into transaction and do MAX(OrderNumber) + 1, but how can I do it in Entity Framework?
You can make OrderNumber an identity column:
class Order
{
public int OrderId { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int OrderNumber { get; set; }
}
By convention, Entity Framework will recognise that OrderId is a primary key; however, it will not automatically be an identity column, so you need so add the DatabaseGenerated(DatabaseGeneratedOption.Identity) to OrderId is you want it to be auto-incrementing.
However, if you don't want to change your database, you can wrap your insertion in a transaction:
using (var transaction = modelContext.BeginTransaction())
{
var newOrderNumber = modelContext.Orders.Max(o => o.OrderNumber) + 1;
var newOrder = new Order { OrderNumber = newOrderNumber };
...
transaction.Commit();
}
And then assign this value plus one to your new Order object.
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; }
I have a really weird situation with one class specifically. Upon adding the class to the DbContext to insert into the database and calling Db.SaveChanges code first/ef is not assigning the primary key id back to the class.
It's really odd, I've never encountered this before and I can't seem to find any solutions online.
Here is what the code looks like currently...
Invoice Code First Class
[Table("invoice")]
public class Invoice
{
[Key]
[Column("invoice_id")]
public int InvoiceId { get; set; }
[Column("invoice_credit_card_payment_id")]
public int InvoiceCreditCardPaymentId { get; set; }
[Column("batch_id")]
public int BatchId { get; set; }
[Column("customer_id")]
public int CustomerId { get; set; }
etc.....
}
Code to Insert Invoice into Database
var invoice = new Invoice()
{
BatchId = 0,
Memo = "",
PayDateTime = DateTime.Now,
QuickbooksAccountName = "",
QuickbooksId = "",
Terms = "",
etc....
};
DbContext.Current.Invoices.Add(invoice);
//Invoice record does insert successfully!
DbContext.Current.SaveChanges();
//This returns ZERO
var id = invoice.InvoiceId;
Additional Notes
As a side note the invoice record is successfully inserted into the database, however, the ID is not assigned back to the invoice object.
Another note - I have around 30 other code first classes that work just fine when doing inserts and getting ID's - it's just this one that is giving me issues for some weird reason.
Per jwatts1980 Recommendation
I updated the invoice class to reflect this
[Key]
[Column("invoice_id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InvoiceId { get; set; }
This did not solve the problem immediately, however it did reveal a new error upon insert:
A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'invoice_id'
I found a stackoverflow answer here which lead me to find some foreign key attributes I had setup on the invoice class:
[ForeignKey("InvoiceId")]
public ICollection<InvoiceOrder> InvoiceOrders { get; set; }
[ForeignKey("InvoiceId")]
public InvoiceCreditCardPayment InvoiceCreditCardPayment { get; set; }
Removing the ForeignKey attributes above seemed to solve the problem so far. I can't say that the it won't cause an other errors, however so far everything appears to be working well.
This attribute might help
[Key]
[Column("invoice_id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InvoiceId { get; set; }