I'm working on http://www.ideliverable.com/blog/writing-an-orchard-webshop-module-from-scratch-part-9
my orchard version is 1.9
OrderRecord.cs
public class OrderRecord
{
public virtual int Id { get; set; }
public virtual int CustomerId { get; set; }
public virtual DateTime CreatedAt { get; set; }
public virtual decimal SubTotal { get; set; }
public virtual decimal Vat { get; set; }
public virtual OrderStatus Status { get; set; }
public virtual IList<OrderDetailRecord> Details { get; private set; }
public virtual string PaymentServiceProviderResponse { get; set; }
public virtual string PaymentReference { get; set; }
public virtual DateTime? PaidAt { get; set; }
public virtual DateTime? CompletedAt { get; set; }
public virtual DateTime? CancelledAt { get; set; }
public virtual decimal Total
{
get { return SubTotal + Vat; }
private set { }
}
public virtual string Number
{
get { return (Id + 1000).ToString(CultureInfo.InvariantCulture); }
private set { }
}
public OrderRecord()
{
Details = new List<OrderDetailRecord>();
}
public virtual void UpdateTotals()
{
var subTotal = 0m;
var vat = 0m;
foreach (var detail in Details)
{
subTotal += detail.SubTotal;
vat += detail.Vat;
}
SubTotal = subTotal;
Vat = vat;
}
No additional content part class because i need to use id and methods are defined in the same class. Field setters that not necessary to create table are defined as private. Total
and Number
Migration.cs
SchemaBuilder.CreateTable("OrderRecord", t => t
.Column<int>("Id", c => c.PrimaryKey().Identity())
.Column<int>("CustomerId", c => c.NotNull())
.Column<DateTime>("CreatedAt", c => c.NotNull())
.Column<decimal>("SubTotal", c => c.NotNull())
.Column<decimal>("Vat", c => c.NotNull())
.Column<string>("Status", c => c.WithLength(50).NotNull())
.Column<string>("PaymentServiceProviderResponse", c => c.WithLength(null))
.Column<string>("PaymentReference", c => c.WithLength(50))
.Column<DateTime>("PaidAt", c => c.Nullable())
.Column<DateTime>("CompletedAt", c => c.Nullable())
.Column<DateTime>("CancelledAt", c => c.Nullable())
);
Table created correctly with these fields but when i want to create an OrderRecord in OrderService.cs with IRepository.Create (T Entity) method, it sends fields not binded to the table. Total
and Number
.
OrderService.cs
public OrderRecord CreateOrder(int customerId, IEnumerable<ShoppingCartItem> items)
{
if (items == null)
throw new ArgumentNullException("items");
// Convert to an array to avoid re-running the enumerable
var itemsArray = items.ToArray();
if (!itemsArray.Any())
throw new ArgumentException("Creating an order with 0 items is not supported", "items");
var order = new OrderRecord
{
CreatedAt = _dateTimeService.Now,
CustomerId = customerId,
Status = OrderStatus.New
};
_orderRepository.Create(order);
Last line throws error here is error log:
2018-04-20 18:37:15,871 [16] Orchard.Exceptions.DefaultExceptionPolicy - Default - An unexpected exception was caught [http://localhost:64607/Orchard.WebShop/Order/Create] NHibernate.Exceptions.GenericADOException: could not insert: [Orchard.Webshop.Models.OrderRecord][SQL: INSERT INTO Orchard_Webshop_OrderRecord (CustomerId, CreatedAt, SubTotal, Vat, Status, PaymentServiceProviderResponse, PaymentReference, PaidAt, CompletedAt, CancelledAt, Total, Number) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Invalid column name 'Total'. Invalid column name 'Number'. Statement(s) could not be prepared.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
1.Create(T entity) in C:\Users\Selman\Orchard-dev\src\Orchard\Data\Repository.cs:line 93
at NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
at NHibernate.Id.IdentityGenerator.InsertSelectDelegate.ExecuteAndExtract(IDbCommand insert, ISessionImplementor session) at NHibernate.Id.Insert.AbstractReturningDelegate.PerformInsert(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder) --- End of inner exception stack trace --- at NHibernate.Id.Insert.AbstractReturningDelegate.PerformInsert(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder) at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Boolean[] notNull, SqlCommandInfo sql, Object obj, ISessionImplementor session) at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Object obj, ISessionImplementor session) at NHibernate.Action.EntityIdentityInsertAction.Execute() at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) at NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event) at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event) at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event) at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event) at NHibernate.Impl.SessionImpl.Save(Object obj) at Orchard.Data.Repository
at Orchard.Data.Repository1.Orchard.Data.IRepository<T>.Create(T entity) in C:\Users\Selman\Orchard-dev\src\Orchard\Data\Repository.cs:line 33
1 items) in C:\Users\Selman\Orchard-dev\src\Orchard.Web\Modules\Orchard.Webshop\Services\OrderService.cs:line 46 at Orchard.Webshop.Controllers.OrderController.Create() in C:\Users\Selman\Orchard-dev\src\Orchard.Web\Modules\Orchard.Webshop\Controllers\OrderController.cs:line 48 at lambda_method(Closure , ControllerBase , Object[] ) at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary
at Orchard.Webshop.Services.OrderService.CreateOrder(Int32 customerId, IEnumerable2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary
2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase
1.End() at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3d() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.b__3f() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.b__3f() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.b__3f()
Solution
I found a solution temporarily. I turned Total
and Number
fields into to methods public virtual decimal Total()
and public virtual string Number()
. It works right now.