Reputation: 1258
I am getting a strange duplicate key exception when trying to insert my order to the database. The order has a User relationship that ties a user to the order.
I am not sure why the duplicate exception is happening as I am grabbing a user from the DB and then assigning it to the order before inserting.
My user context is just an IRepository of User.
Info
Ctor
public OrderManagerController(IRepository<Order> orderContext,
IRepository<User> userContext)
{
_orderContext = orderContext;
userContext = userContext;
}
Ninject Binding
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
//Bind concrete classes to contracts
kernel.Bind<IRepository<Order>>().To<SQLRepository<Order>>();
kernel.Bind<IRepository<User>>().To<SQLRepository<User>>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
Action
[HttpPost]
public ActionResult Create(OrderManagerViewModel order)
{
if (!ModelState.IsValid)
return View("Create", order);
else
{
User user = _userContext.Find(order.AssignedUserId); // Grab user from DB
//Create the order from the passed in view model and DB user
Order orderToInsert = new Order
{
AssignedUser = user,
Category = order.Category,
Comments = order.Comments,
CustomerName = order.CustomerName,
EstimatedHours = order.EstimatedHours,
SalesOrderNumber = order.SalesOrderNumber,
LineType = order.LineType,
OrderTotal = order.OrderTotal,
ScheduledCompletionDate = order.ScheduledCompletionDate,
OutDate = order.OutDate
};
_orderContext.Insert(orderToInsert); // Insert
_orderContext.Commit();//Save -----Crashes with Duplicate Exception on AssignedUser.Id
return RedirectToAction("Index");
}
}
OrderManagerViewModel
public class OrderManagerViewModel
{
[RegularExpression(@"^([0-9]{8})$", ErrorMessage = "Sales order number must be 8 digits.")]
[DisplayName("Sales Order Number")]
[Range(10000000, 99999999)]
public int SalesOrderNumber { get; set; }
[DisplayName("Engineer Line Type")]
[Range(1, 3)]
public int LineType { get; set; }
[Range(0, 240)]
[DisplayName("Estimated Hours")]
public int EstimatedHours { get; set; }
[StringLength(50)]
[DisplayName("Customer Name")]
public string CustomerName { get; set; }
[Range(0, 2000000)]
[DisplayName("Order Total")]
public decimal OrderTotal { get; set; }
[StringLength(2)]
[DisplayName("PA/SB")]
public string Category { get; set; }
public string FirstName { get; set; }
public string AssignedUserId { get; set; }
[DisplayName("Scheduled Date Out")]
public DateTime? ScheduledCompletionDate { get; set; }
[Display(Name = "Out Date")]
public DateTime OutDate { get; set; }
[StringLength(500)]
public string Comments { get; set; }
}
Order
public class Order : BaseEntity
{
[RegularExpression(@"^([0-9]{8})$", ErrorMessage = "Sales order number must be 8 digits.")]
[DisplayName("Sales Order Number")]
[Range(10000000,99999999)]
public int SalesOrderNumber { get; set; }
[DisplayName("Engineer Line Type")]
[Range(1,3)]
public int LineType { get; set; }
[Range(0,120)]
[DisplayName("Engineering Hours")]
public int EngineeringHours { get; set; }
[Range(0, 120)]
[DisplayName("Drafting Hours")]
public int DraftingHours { get; set; }
[Range(0, 240)]
[DisplayName("Estimated Hours")]
public int EstimatedHours { get; set; }
[StringLength(50)]
[DisplayName("Customer Name")]
public string CustomerName { get; set; }
[Range(0,2000000)]
[DisplayName("Order Total")]
public decimal OrderTotal { get; set; }
[StringLength(2)]
[DisplayName("PA/SB")]
public string Category { get; set; }
[DisplayName("Check Out Time")]
public DateTime? CheckedOutDate { get; set; }
[Required]
public User AssignedUser { get; set; }
[DisplayName("Scheduled Date Out")]
public DateTime? ScheduledCompletionDate { get; set; }
[Display(Name = "Out Date")]
public DateTime OutDate { get; set; }
[DisplayName("Actual Date Out")]
public DateTime? ActualCompletionDate { get; set; }
[StringLength(500)]
public string Comments { get; set; }
}
Base Entity
public abstract class BaseEntity
{
public string Id { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public BaseEntity()
{
Id = Guid.NewGuid().ToString();
CreatedAt = DateTime.Now;
}
}
IRepository implementation
public class SQLRepository<T> : IRepository<T> where T : BaseEntity
{
internal DataContext context;
internal DbSet<T> dbSet;
public SQLRepository(DataContext context)
{
this.context = context;
dbSet = context.Set<T>();
}
public IQueryable<T> Collection()
{
return dbSet;
}
public void Commit()
{
context.SaveChanges();
}
public void Delete(string Id)
{
var t = Find(Id);
if (context.Entry(t).State == EntityState.Detached)
dbSet.Attach(t);
dbSet.Remove(t);
}
public T Find(string Id)
{
return dbSet.Find(Id);
}
public void Insert(T t)
{
dbSet.Add(t);
}
public void Update(T t)
{
dbSet.Attach(t);
context.Entry(t).State = EntityState.Modified;
}
}
Not sure if maybe I am misunderstanding something.
Upvotes: 0
Views: 609
Reputation: 9153
It looks like the issue is because your User and Order are coming from separate contexts...I don't see where you're registering your DbContext in ninject but you want to make sure to register it in request scope. That will ensure that you get the same context for all operations within a single request.
Upvotes: 1