Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #425 from danielkzu/priced-order-view-model-autono…

…mous

Made priced order view model generator autonomous
Reviewed
  • Loading branch information...
commit a66fd1f916cc8b6a6ad22fb51df772f1ebaec5e2 2 parents 3b0bee1 + 9a672c7
@fsimonazzi fsimonazzi authored
View
17 scripts/CreateDatabaseObjects.sql
@@ -90,6 +90,19 @@ SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
+CREATE TABLE [ConferenceRegistration].[PricedOrderLineSeatTypeDescriptions](
+ [SeatTypeId] [uniqueidentifier] NOT NULL,
+ [Name] [nvarchar](max) NULL,
+PRIMARY KEY CLUSTERED
+(
+ [SeatTypeId] ASC
+)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
+)
+GO
+SET ANSI_NULLS ON
+GO
+SET QUOTED_IDENTIFIER ON
+GO
CREATE TABLE [ConferenceManagement].[Conferences](
[Id] [uniqueidentifier] NOT NULL,
[AccessCode] [nvarchar](6) NULL,
@@ -262,8 +275,8 @@ SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [ConferenceManagement].[SeatTypes](
[Id] [uniqueidentifier] NOT NULL,
- [Name] [nvarchar](max) NOT NULL,
- [Description] [nvarchar](max) NOT NULL,
+ [Name] [nvarchar](70) NOT NULL,
+ [Description] [nvarchar](250) NOT NULL,
[Quantity] [int] NOT NULL,
[Price] [decimal](18, 2) NOT NULL,
[ConferenceInfo_Id] [uniqueidentifier] NOT NULL,
View
126 source/Conference/Registration.IntegrationTests/PricedOrderViewModelGeneratorFixture.cs
@@ -14,9 +14,8 @@
namespace Registration.IntegrationTests.PricedOrderViewModelGeneratorFixture
{
using System;
- using System.Collections.Generic;
+ using Conference;
using Infrastructure.Serialization;
- using Moq;
using Registration.Events;
using Registration.Handlers;
using Registration.ReadModel;
@@ -25,26 +24,31 @@ namespace Registration.IntegrationTests.PricedOrderViewModelGeneratorFixture
public class given_a_read_model_generator : given_a_read_model_database
{
- private static readonly List<SeatTypeName> seatTypes = new List<SeatTypeName>
- {
- new SeatTypeName { Id = Guid.NewGuid(), Name= "General" },
- new SeatTypeName { Id = Guid.NewGuid(), Name= "Precon" },
- };
-
protected PricedOrderViewModelGenerator sut;
private IOrderDao dao;
public given_a_read_model_generator()
{
- var conferenceDao = new Mock<IConferenceDao>();
- conferenceDao.Setup(x => x.GetSeatTypeNames(It.IsAny<IEnumerable<Guid>>()))
- .Returns(seatTypes);
-
- this.sut = new PricedOrderViewModelGenerator(conferenceDao.Object, () => new ConferenceRegistrationDbContext(dbName));
+ this.sut = new PricedOrderViewModelGenerator(() => new ConferenceRegistrationDbContext(dbName));
this.dao = new OrderDao(() => new ConferenceRegistrationDbContext(dbName), new MemoryBlobStorage(), new JsonTextSerializer());
}
- public class given_a_calculated_order : given_a_read_model_generator
+ public class given_some_initial_seats : given_a_read_model_generator
+ {
+ protected SeatCreated[] seatCreatedEvents;
+ public given_some_initial_seats()
+ {
+ this.seatCreatedEvents = new[]
+ {
+ new SeatCreated { SourceId = Guid.NewGuid(), Name = "General" },
+ new SeatCreated { SourceId = Guid.NewGuid(), Name = "Precon" }
+ };
+ this.sut.Handle(this.seatCreatedEvents[0]);
+ this.sut.Handle(this.seatCreatedEvents[1]);
+ }
+ }
+
+ public class given_a_calculated_order : given_some_initial_seats
{
private static readonly Guid orderId = Guid.NewGuid();
@@ -60,7 +64,7 @@ public given_a_calculated_order()
new SeatOrderLine
{
LineTotal = 50,
- SeatType = seatTypes[0].Id,
+ SeatType = this.seatCreatedEvents[0].SourceId,
Quantity = 10,
UnitPrice = 5
},
@@ -111,7 +115,7 @@ public void when_recalculated_then_replaces_line()
new SeatOrderLine
{
LineTotal = 20,
- SeatType = seatTypes[1].Id,
+ SeatType = this.seatCreatedEvents[1].SourceId,
Quantity = 2,
UnitPrice = 10
},
@@ -150,7 +154,95 @@ public void when_seat_assignments_created_then_updates_order_with_assignments_id
Assert.Equal(assignmentsId, dto.AssignmentsId);
}
}
- }
+ public class given_changes_to_seats : given_some_initial_seats
+ {
+ protected SeatUpdated[] seatUpdatedEvents;
+ public given_changes_to_seats()
+ {
+ this.seatUpdatedEvents = new[]
+ {
+ new SeatUpdated { SourceId = seatCreatedEvents[0].SourceId, Name = "General_Updated" },
+ new SeatUpdated { SourceId = seatCreatedEvents[1].SourceId, Name = "Precon_Updated" },
+ };
+ this.sut.Handle(this.seatUpdatedEvents[0]);
+ }
+ }
+
+ public class given_a_new_calculated_order : given_changes_to_seats
+ {
+ private static readonly Guid orderId = Guid.NewGuid();
+
+ private PricedOrder dto;
+ public given_a_new_calculated_order()
+ {
+ this.sut.Handle(new OrderTotalsCalculated
+ {
+ SourceId = orderId,
+ Lines = new[]
+ {
+ new SeatOrderLine
+ {
+ LineTotal = 50,
+ SeatType = this.seatCreatedEvents[0].SourceId,
+ Quantity = 10,
+ UnitPrice = 5
+ },
+ new SeatOrderLine
+ {
+ LineTotal = 10,
+ SeatType = this.seatCreatedEvents[1].SourceId,
+ Quantity = 1,
+ UnitPrice = 10
+ },
+ },
+ Total = 60,
+ IsFreeOfCharge = true
+ });
+
+ this.dto = this.dao.FindPricedOrder(orderId);
+ }
+
+ [Fact]
+ public void then_populates_with_updated_description()
+ {
+ Assert.Equal("General_Updated", dto.Lines[0].Description);
+ Assert.Equal("Precon", dto.Lines[1].Description);
+ }
+
+ [Fact]
+ public void when_recalculated__after_new_update_then_replaces_line()
+ {
+ this.sut.Handle(seatUpdatedEvents[1]);
+ this.sut.Handle(new OrderTotalsCalculated
+ {
+ SourceId = orderId,
+ Lines = new[]
+ {
+ new SeatOrderLine
+ {
+ LineTotal = 10,
+ SeatType = this.seatCreatedEvents[0].SourceId,
+ Quantity = 2,
+ UnitPrice = 5
+ },
+ new SeatOrderLine
+ {
+ LineTotal = 20,
+ SeatType = this.seatCreatedEvents[1].SourceId,
+ Quantity = 2,
+ UnitPrice = 10
+ },
+ },
+ Total = 30,
+ });
+
+ var dto = this.dao.FindPricedOrder(orderId);
+
+ Assert.Equal("General_Updated", dto.Lines[0].Description);
+ Assert.Equal("Precon_Updated", dto.Lines[1].Description);
+ }
+ }
+ }
}
View
59 source/Conference/Registration/Handlers/PricedOrderViewModelGenerator.cs
@@ -14,9 +14,11 @@
namespace Registration.Handlers
{
using System;
+ using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Linq;
+ using Conference;
using Infrastructure.Messaging.Handling;
using Registration.Events;
using Registration.ReadModel;
@@ -25,20 +27,20 @@ namespace Registration.Handlers
public class PricedOrderViewModelGenerator :
IEventHandler<OrderTotalsCalculated>,
IEventHandler<OrderExpired>,
- IEventHandler<SeatAssignmentsCreated>
+ IEventHandler<SeatAssignmentsCreated>,
+ IEventHandler<SeatCreated>,
+ IEventHandler<SeatUpdated>
{
private readonly Func<ConferenceRegistrationDbContext> contextFactory;
- private IConferenceDao conferenceDao;
- public PricedOrderViewModelGenerator(IConferenceDao conferenceDao, Func<ConferenceRegistrationDbContext> contextFactory)
+ public PricedOrderViewModelGenerator(Func<ConferenceRegistrationDbContext> contextFactory)
{
- this.conferenceDao = conferenceDao;
this.contextFactory = contextFactory;
}
public void Handle(OrderTotalsCalculated @event)
{
- var seatTypeIds = @event.Lines.OfType<SeatOrderLine>().Select(x => x.SeatType).ToArray();
+ var seatTypeIds = @event.Lines.OfType<SeatOrderLine>().Select(x => x.SeatType).Distinct().ToArray();
using (var context = this.contextFactory.Invoke())
{
var dto = context.Query<PricedOrder>().Include(x => x.Lines).FirstOrDefault(x => x.OrderId == @event.SourceId);
@@ -56,7 +58,17 @@ public void Handle(OrderTotalsCalculated @event)
}
}
- var seatTypeDescriptions = this.conferenceDao.GetSeatTypeNames(seatTypeIds);
+ List<PricedOrderLineSeatTypeDescription> seatTypeDescriptions;
+ if (seatTypeIds.Length != 0)
+ {
+ seatTypeDescriptions = context.Query<PricedOrderLineSeatTypeDescription>()
+ .Where(x => seatTypeIds.Contains(x.SeatTypeId))
+ .ToList();
+ }
+ else
+ {
+ seatTypeDescriptions = new List<PricedOrderLineSeatTypeDescription>();
+ }
foreach (var orderLine in @event.Lines)
{
@@ -68,7 +80,8 @@ public void Handle(OrderTotalsCalculated @event)
var seatOrderLine = orderLine as SeatOrderLine;
if (seatOrderLine != null)
{
- line.Description = seatTypeDescriptions.Where(x => x.Id == seatOrderLine.SeatType).Select(x => x.Name).FirstOrDefault();
+ // should we update the view model to avoid loosing the SeatTypeId?
+ line.Description = seatTypeDescriptions.Where(x => x.SeatTypeId == seatOrderLine.SeatType).Select(x => x.Name).FirstOrDefault();
line.UnitPrice = seatOrderLine.UnitPrice;
line.Quantity = seatOrderLine.Quantity;
}
@@ -121,5 +134,37 @@ public void Handle(SeatAssignmentsCreated @event)
}
}
}
+
+ public void Handle(SeatCreated @event)
+ {
+ using (var context = this.contextFactory.Invoke())
+ {
+ var dto = context.Find<PricedOrderLineSeatTypeDescription>(@event.SourceId);
+ if (dto == null)
+ {
+ dto = new PricedOrderLineSeatTypeDescription { SeatTypeId = @event.SourceId };
+ context.Set<PricedOrderLineSeatTypeDescription>().Add(dto);
+ }
+
+ dto.Name = @event.Name;
+ context.SaveChanges();
+ }
+ }
+
+ public void Handle(SeatUpdated @event)
+ {
+ using (var context = this.contextFactory.Invoke())
+ {
+ var dto = context.Find<PricedOrderLineSeatTypeDescription>(@event.SourceId);
+ if (dto == null)
+ {
+ dto = new PricedOrderLineSeatTypeDescription { SeatTypeId = @event.SourceId };
+ context.Set<PricedOrderLineSeatTypeDescription>().Add(dto);
+ }
+
+ dto.Name = @event.Name;
+ context.SaveChanges();
+ }
+ }
}
}
View
1  source/Conference/Registration/ReadModel/Implementation/ConferenceRegistrationDbContext.cs
@@ -40,6 +40,7 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<PricedOrder>().ToTable("PricedOrders", SchemaName);
modelBuilder.Entity<PricedOrder>().HasMany(c => c.Lines).WithRequired().HasForeignKey(x => x.OrderId);
modelBuilder.Entity<PricedOrderLine>().ToTable("PricedOrderLines", SchemaName);
+ modelBuilder.Entity<PricedOrderLineSeatTypeDescription>().ToTable("PricedOrderLineSeatTypeDescriptions", SchemaName);
modelBuilder.Entity<Conference>().ToTable("ConferencesView", SchemaName);
modelBuilder.Entity<Conference>().HasMany(c => c.Seats).WithRequired();
View
25 source/Conference/Registration/ReadModel/PricedOrderLineSeatTypeDescription.cs
@@ -0,0 +1,25 @@
+// ==============================================================================================================
+// Microsoft patterns & practices
+// CQRS Journey project
+// ==============================================================================================================
+// ©2012 Microsoft. All rights reserved. Certain content used with permission from contributors
+// http://cqrsjourney.github.com/contributors/members
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software distributed under the License is
+// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and limitations under the License.
+// ==============================================================================================================
+
+namespace Registration.ReadModel
+{
+ using System;
+ using System.ComponentModel.DataAnnotations;
+
+ internal class PricedOrderLineSeatTypeDescription
+ {
+ [Key]
+ public Guid SeatTypeId { get; set; }
+ public string Name { get; set; }
+ }
+}
View
1  source/Conference/Registration/Registration.csproj
@@ -81,6 +81,7 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="ReadModel\ConferenceAlias.cs" />
+ <Compile Include="ReadModel\PricedOrderLineSeatTypeDescription.cs" />
<Compile Include="ReadModel\OrderSeat.cs" />
<Compile Include="ReadModel\Implementation\OrderDao.cs" />
<Compile Include="ReadModel\Implementation\ConferenceRegistrationDbContext.cs" />
Please sign in to comment.
Something went wrong with that request. Please try again.