I'm new to Entity Framework, have a issue of a Saving header and detailed records properly in a layered application
These are my model classes:
public class SalesOrderHeader
{
public SalesOrderHeader()
{
this.SalesPerson = new SalesPerson();
this.Customer = new Customer();
}
public int Id { get; set; }
//public int CustId { get; set; }
public string CustName { get; set; }
public string CustCity { get; set; }
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
public System.DateTime PostingDate { get; set; }
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
public System.DateTime OrderDate { get; set; }
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
public System.DateTime DocumentDate { get; set; }
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
public System.DateTime DeliveryDate { get; set; }
public bool Status { get; set; }
public decimal SoDiscountAmount { get; set; }
public decimal SoTotal { get; set; }
public decimal SoDiscount { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<SalesOrderDetail> SalesOrderDetails { get; set; }
public virtual SalesPerson SalesPerson { get; set; }
}
public class SalesOrderDetail
{
public SalesOrderDetail()
{
this.Item = new Item();
this.SalesOrderHeader = new SalesOrderHeader();
}
public int Id { get; set; }
[ForeignKey("SalesOrderHeader")]
public int? SoId { get; set; }
public string ItemCode { get; set; }
public string ItemDescription { get; set; }
public string LocationCode { get; set; }
public int Quantity { get; set; }
public string UOM { get; set; }
public decimal UnitPrice { get; set; }
public decimal LineAmount { get; set; }
public decimal LineDiscount { get; set; }
public virtual Item Item { get; set; }
public virtual SalesOrderHeader SalesOrderHeader { get; set; }
}
public class Item
{
public Item()
{
this.UnitofMeasure = new UnitofMeasure();
this.ItemCategory = new ItemCategory();
}
public int Id { get; set; }
public string ItemCode { get; set; }
public string ItemDescription { get; set; }
public int StockQuantity { get; set; }
public decimal UnitPrice { get; set; }
//public int CategoryId { get; set; }
public virtual ItemCategory ItemCategory { get; set; }
//public int UOMId { get; set; }
public virtual UnitofMeasure UnitofMeasure { get; set; }
public virtual ICollection<SalesOrderDetail> SalesOrderDetails { get; set; }
}
public class ItemCategory
{
public int Id { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
public class UnitofMeasure
{
public int Id { get; set; }
public string UOM { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
Form Code
private void GetUIDetailData(SalesOrderHeader h)
{
h.SalesOrderDetails = new List<SalesOrderDetail>();
try
{
for (int i = 0; i < dgSODetails.Rows.Count - 1 ; i++)
{
SalesOrderDetail x = new SalesOrderDetail();
//x.SalesOrderHeader.Id = h.Id;
x.SalesOrderHeader = h;
string _code = dgSODetails.Rows[i].Cells[1].Value.ToString();
Item _item = _ItemShareMgr.LoadItemByCode(_code);
x.Item.Id = _item.Id;
x.ItemCode = _code;
x.ItemDescription = dgSODetails.Rows[i].Cells[2].Value.ToString();
x.LocationCode = dgSODetails.Rows[i].Cells[3].Value.ToString();
x.Quantity = int.Parse(dgSODetails.Rows[i].Cells[4].Value.ToString());
x.UOM = dgSODetails.Rows[i].Cells[5].Value.ToString();
x.UnitPrice = decimal.Parse(dgSODetails.Rows[i].Cells[6].Value.ToString());
//x.LineAmount = decimal.Parse(dgSODetails.Rows[i].Cells[8].Value.ToString());
x.LineDiscount = decimal.Parse(dgSODetails.Rows[i].Cells[7].Value.ToString());
h.SalesOrderDetails.Add(x);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private SalesOrderHeader GetUIHeaderData()
{
SalesOrderHeader _soheader = new SalesOrderHeader();
try
{
_soheader.CustName = cmbCustomerName.Text;
_soheader.CustCity = textBoxCity.Text;
_soheader.DocumentDate = dtDocDate.Value;
_soheader.DeliveryDate = dtDeliveryDate.Value;
_soheader.SalesPerson.Id = _SalesPersonShareMgr.LoadSalesPersonByName(cmbSalesPerson.Text).Id;
_soheader.Customer = _CustShareMgr.LoadCustomerByName(cmbCustomerName.Text);
_soheader.DocumentDate = dtDocDate.Value;
_soheader.PostingDate = dtPostingDate.Value;
_soheader.OrderDate = dtOrderDate.Value;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
return _soheader;
}
private void buttonSave_Click(object sender, EventArgs e)
{
try
{
SalesOrderHeader objH = GetUIHeaderData();
GetUIDetailData(objH);
_SOHeaderSharedMgr.SaveSOHeader(objH);
MessageBox.Show("Sales Order Saved !");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Data Layer Code
public void SaveSOHeader(SalesOrderHeader SO)
{
try
{
using (SODBContext db = new SODBContext())
{
db.Entry(SO.SalesPerson).State = EntityState.Unchanged;
db.Entry(SO.Customer).State = EntityState.Unchanged;
db.Entry(SO.Customer.CustCity).State = EntityState.Unchanged;
db.SalesOrderHeaders.Add(SO);
foreach (SalesOrderDetail line in SO.SalesOrderDetails)
{
//line.SalesOrderHeader = SO;
db.Entry(line.Item).State = EntityState.Unchanged;
db.Entry(line.Item.UnitofMeasure).State = EntityState.Unchanged;
db.Entry(line.Item.ItemCategory).State = EntityState.Unchanged;
db.SalesOrderDetails.Add(line);
}
db.Entry(SO).State = EntityState.Added;
db.SaveChanges();
}
}
catch (Exception ex)
{
throw ex;
}
}
The question is this:
when I comment below code
db.Entry(line.Item).State = EntityState.Unchanged;
db.Entry(line.Item.UnitofMeasure).State = EntityState.Unchanged;
db.Entry(line.Item.ItemCategory).State = EntityState.Unchanged;
will result a duplication of record for Item , Item Category & , Unit of Measure Uncomment this will result
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.
This is a layered application
I need some expert advice to resolve this issue.