Skip to content

Commit

Permalink
Stand Ende des Webinars vom 14.04.2016, Readme aktualisiert
Browse files Browse the repository at this point in the history
  • Loading branch information
janderit committed Apr 14, 2016
1 parent 964bbb2 commit f33b214
Show file tree
Hide file tree
Showing 14 changed files with 65 additions and 24 deletions.
4 changes: 3 additions & 1 deletion Api/Warenwirtschaft/WarenwirtschaftProxy.cs
Expand Up @@ -38,7 +38,9 @@ public void Einlisten(Guid produkt, string bezeichnung)

public void Nachbestellen(Guid lagerId, Guid produkt, int menge)
{
_port.Handle(new CommandEnvelope(new NachbestellungBeauftragen(lagerId:lagerId, produktId: produkt, bestellteMenge: menge)));
_port.Handle(new CommandEnvelope(
new NachbestellungBeauftragen(lagerId: lagerId, produktId: produkt, bestellteMenge: menge)
));
}

public void WareneingangVerzeichnen(Guid lagerId, Guid produkt)
Expand Down
11 changes: 10 additions & 1 deletion Frontend/CqrsGmbH_Web.cs
Expand Up @@ -11,9 +11,18 @@ public abstract class CqrsGmbH_Web : NancyModule
{
static CqrsGmbH_Web()
{
// *************** Hier kann man zwischen Event Sourcing und SQL umstellen. Achtung: nur Event Sourcing ist voll implementiert.

var store = new InMemoryEventStore();
var port = new CqrsHost(store);

// -oder -

/*
var ConnectionString = "";
var port = new CqrsHost_SQL(() => new SqlConnection(ConnectionString));
*/

_api = new Lazy<CqrsGmbH>( // <-- statt IoC
() =>
{
Expand Down Expand Up @@ -43,4 +52,4 @@ protected CqrsGmbH Api()
return _api.Value;
}
}
}
}
5 changes: 5 additions & 0 deletions Frontend/Frontend.csproj
Expand Up @@ -61,6 +61,7 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -127,6 +128,10 @@
<Project>{fada883e-b7c1-47b5-8ac2-21fe84fc3e79}</Project>
<Name>Modell_shared</Name>
</ProjectReference>
<ProjectReference Include="..\Modell_SQL\Modell_SQL.csproj">
<Project>{C102530D-83DD-456E-A294-F51BC3E135E1}</Project>
<Name>Modell_SQL</Name>
</ProjectReference>
<ProjectReference Include="..\Resourcen\Resourcen.csproj">
<Project>{8A34516F-5D6E-4A70-A821-408DEA3C44FC}</Project>
<Name>Resourcen</Name>
Expand Down
4 changes: 2 additions & 2 deletions Modell_EventSourced/Host/CqrsHost.AbfrageKonfiguration.cs
Expand Up @@ -42,7 +42,7 @@ private Produktliste Handle(QueryEnvelope queryEnvelope, ProduktlisteAbfrage abf
private List<ProduktInfo> AlleProduktInfos()
{
var alle_produkt_ids = ProduktProjektion.AlleIDs(_eventStore.History);
var produkte = alle_produkt_ids.Select(_ => _produkte.Access(_)).ToList();
var produkte = alle_produkt_ids.Select(_ => _produkte.ProduktInfoLesen(_)).ToList();
return produkte;
}

Expand Down Expand Up @@ -71,7 +71,7 @@ private Bestellungenliste Handle(QueryEnvelope queryEnvelope, OffeneBestellungen
foreach (var bestellung in result.Bestellungen)
{
bestellung.Kundenname = _kunden.Access(bestellung.Kunde).Name;
bestellung.Produktname = _produkte.Access(bestellung.Produkt).Bezeichnung;
bestellung.Produktname = _produkte.ProduktInfoLesen(bestellung.Produkt).Bezeichnung;
}
return result;
}
Expand Down
17 changes: 12 additions & 5 deletions Modell_EventSourced/Host/CqrsHost.BefehlsKonfiguration.cs
Expand Up @@ -24,9 +24,16 @@ private void Handle(CommandEnvelope commandEnvelope, KundeErfassen aktion, UnitO

private void Handle(CommandEnvelope commandEnvelope, AnschriftAendern aktion, UnitOfWork unitOfWork)
{
var kunde = new KundeRepository(unitOfWork).Retrieve(aktion.KundenId);
kunde.AnschriftAendern(aktion.NeueAnschrift);
unitOfWork.Commit();
try
{
var kunde = new KundeRepository(unitOfWork).Retrieve(aktion.KundenId);
kunde.AnschriftAendern(aktion.NeueAnschrift);
unitOfWork.Commit();
}
catch (Exception ex)
{
// Protokollieren
}
}

private void Handle(CommandEnvelope commandEnvelope, AuftragErfassen aktion, UnitOfWork unitOfWork)
Expand Down Expand Up @@ -54,8 +61,8 @@ private void Handle(CommandEnvelope commandEnvelope, ProduktEinlisten aktion, Un

private void Handle(CommandEnvelope commandEnvelope, NachbestellungBeauftragen aktion, UnitOfWork unitOfWork)
{
var produkt = new LagerRepository(unitOfWork).Retrieve(aktion.LagerId, aktion.ProduktId);
produkt.Nachbestellen(aktion.BestellteMenge);
var lager = new LagerRepository(unitOfWork).Retrieve(aktion.LagerId, aktion.ProduktId);
lager.Nachbestellen(aktion.BestellteMenge);
}

private void Handle(CommandEnvelope commandEnvelope, WareneingangVerbuchen aktion, UnitOfWork unitOfWork)
Expand Down
2 changes: 1 addition & 1 deletion Modell_EventSourced/Host/CqrsHost.cs
Expand Up @@ -30,7 +30,7 @@ public CqrsHost(EventStore eventStore)
_kunden = new KundeReadmodel(_eventStore.Stream(Kunde.AggregateEvents.Filter));
_auftraege = new AuftragReadmodel(_eventStore.Stream(Auftrag.AggregateEvents.Filter), ()=>_eventStore.History);
_produkte = new ProduktReadmodel(_eventStore.Stream(Produkt.AggregateEvents.Filter));
_lagerbestand = new LagerbestandReadmodel(_eventStore.Stream(Lagerposten.AggregateEvents.Filter), _produkte.Access);
_lagerbestand = new LagerbestandReadmodel(_eventStore.Stream(Lagerposten.AggregateEvents.Filter), _produkte.ProduktInfoLesen);
_warenkoerbe = new WarenkorbReadmodel(_eventStore.Stream(Warenkorb.AggregateEvents.Filter));
_meta = new MetaReadmodel(_eventStore.Subscribe);

Expand Down
2 changes: 1 addition & 1 deletion Modell_EventSourced/Readmodels/ProduktReadmodel.cs
Expand Up @@ -17,7 +17,7 @@ public ProduktReadmodel(Func<Guid, IEnumerable<Ereignis>> history)
_history = history;
}

public ProduktInfo Access(Guid produkt)
public ProduktInfo ProduktInfoLesen(Guid produkt)
{
var history = _history(produkt).ToList();
var projektor = new ProduktProjektion(produkt, () => history);
Expand Down
Expand Up @@ -10,7 +10,8 @@ public sealed class NachbestellungWurdeBeauftragt

public override string ToString()
{
return "Eine Nachbestellung über " + Menge + "x {ID:" + Produkt + "} nach {ID:" + Lager + "} wurde beauftragt.";
return "Eine Nachbestellung über " + Menge
+ "x {ID:" + Produkt + "} nach {ID:" + Lager + "} wurde beauftragt.";
}
}
}
5 changes: 4 additions & 1 deletion Modell_EventSourced/Warenwirtschaft/ProduktProjektion.cs
Expand Up @@ -12,7 +12,10 @@ public sealed partial class ProduktProjektion

public static IEnumerable<Guid> AlleIDs(IEnumerable<Ereignis> history)
{
return history.OfType<Ereignis<ProduktWurdeEingelistet>>().Select(_ => _.Daten.Produkt).ToList();
return history
.OfType<Ereignis<ProduktWurdeEingelistet>>()
.Select(_ => _.Daten.Produkt)
.ToList();
}

private readonly Func<IEnumerable<Ereignis>> _history;
Expand Down
15 changes: 8 additions & 7 deletions Modell_SQL/CqrsHost_SQL_Abfragen.cs
Expand Up @@ -3,14 +3,10 @@
using System.Linq;
using System.Text.RegularExpressions;
using Api.Bestellwesen.Abfragen;
using Api.Bestellwesen.Aktionen;
using Api.Kunden.Abfragen;
using Api.Kunden.Aktionen;
using Api.Meta;
using Api.Warenkorb.Abfragen;
using Api.Warenkorb.Aktionen;
using Api.Warenwirtschaft.Abfragen;
using Api.Warenwirtschaft.Aktionen;
using Infrastruktur.Messaging;
using Resourcen.Bestellwesen;
using Resourcen.Kunden;
Expand All @@ -37,14 +33,19 @@ private Produktliste Handle(QueryEnvelope queryEnvelope, ProduktlisteAbfrage abf
return new ProduktRepository(db).Retrieve();
}
}

/*private ProduktlisteEx Handle(QueryEnvelope queryEnvelope, ProduktlisteExAbfrage abfrage)
/*
private ProduktlisteEx Handle(QueryEnvelope queryEnvelope, ProduktlisteExAbfrage abfrage)
{
using (var db = ReadAccess())
{
var lagerbestand =
new LagerbestandRepository(db).RetrieveAlleStandorte()
.Bestand.GroupBy(_=>_.Produkt).ToDictionary(_=>_.Key, _=>new { Bestand = _.Sum(x=>x.LagerBestand), Zulauf = _.Sum(x => x.MengeImZulauf) });
.Bestand.GroupBy(_=>_.Produkt).ToDictionary(_=>_.Key, _=>
new
{
Bestand = _.Sum(x=>x.LagerBestand),
Zulauf = _.Sum(x => x.MengeImZulauf)
});
return new ProduktlisteEx {Produkte = new ProduktRepository(db).Retrieve().Produkte.Select(
p => new ProduktInfoEx
Expand Down
2 changes: 0 additions & 2 deletions Modell_SQL/LagerbestandRepository.cs
Expand Up @@ -151,7 +151,6 @@ public void Set_Zulauf(Guid lager, Guid produkt, int zulauf)
setpar("zulauf", zulauf);
}
);

ProduktExDenormalizer.Update(_sql, produkt);
}

Expand All @@ -166,7 +165,6 @@ public void Set_Bestand(Guid lager, Guid produkt, int bestand)
setpar("bestand", bestand);
}
);

ProduktExDenormalizer.Update(_sql, produkt);
}

Expand Down
13 changes: 13 additions & 0 deletions README.md
Expand Up @@ -7,6 +7,17 @@ c# Beispielprojekt mit einer minimalistischen CQRS-Struktur
Ziel dieses Projekts ist eine CQRS Beispielanwendung in c# mit einem besonderen Ansatz. Um die wesentlichen Elemente von CQRS deutlich herauszustellen, verzichte ich auf viele - oft auch unreflektiert angewandte - Optimierungen und Abstraktionen.



Stand

Aktuell (2016-04-14) ist das Modell mit Event Sourcing gut testabgedeckt und vollständig implementiert. Ein zweites alternatives Modell mit SQL Zugriff ist
nur lückenhaft implementiert.

Zwischen beiden Modellen können Sie für die Tests in "Spezifikation.cs" und für das echte System in CqrsGmbH_Web.cs umstellen. Für die SQL Variante sind Connection Strings notwendig! Die Tests erstellen Datenbank "cqrsdemo_test" und Tabellen automatisch. Das Echtsystem benötigt dann eine Db mit identischer Struktur.




Vorbemerkungen

Vorweg zwei Hinweise: Die Motivation dieses Codes ist es, die Konzepte einer CQRS + Event Sourcing Anwendung zu zeigen, möglichst freigelegt von allem Ballast. Das Ergebnis ist eine klar strukturierte Anwendung mit sehr starker Entkopplung.
Expand All @@ -27,3 +38,5 @@ In der Fachdomäne des Beispielprojekts geht es um eine - recht triviale - Waren
Die wesentlichen Begriffe der Fachdomäne sind "Kunde", "Auftrag", "Produkt", "Nachbestellung", "Wareneingang", "Lagerbestand" und "Verfügbarkeit". Dabei ist die Verfügbarkeit der Lagerbestand abzüglich bereits erfasster Aufträge zuzüglich im Zulauf befindlicher Nachbestellungen. Liefertermine werden nicht berücksichtigt.

Dabei treffe ich eine Reihe etwas unrealistischer Annahmen: ein Kundenname besteht aus einer Zeichenkette, ebenso seine Adresse. Ein Auftrag enthält nur eine Position mit genau einem Produkt, allerdings mit einer variablen Menge. Preisangaben werden weder im Einkauf noch im Verkauf berücksichtigt.


5 changes: 3 additions & 2 deletions Spezifikation/Spezifikation.cs
Expand Up @@ -3,8 +3,9 @@

namespace Spezifikation
{
// Schalterklasse, um das System zwischen LegacySQL, CQRS_SQL und CQRS_EventSourcing, umzustellen
public class Spezifikation : Spezifikation_CQRS_SQL
// Schalterklasse, um das System zwischen CQRS_SQL und CQRS_EventSourcing umzustellen
public class Spezifikation : Spezifikation_Eventsourcing
//public class Spezifikation : Spezifikation_CQRS_SQL
{
protected static Guid TestKundeEinrichten(CqrsGmbH testsystem, string name, string anschrift)
{
Expand Down
1 change: 1 addition & 0 deletions Spezifikation/Spezifikation_CQRS_SQL.cs
Expand Up @@ -60,6 +60,7 @@ public void TestCaseSetup()
db.ExecuteNonQuery(@"DELETE FROM [kunden]");
db.ExecuteNonQuery(@"DELETE FROM [produkte]");
db.ExecuteNonQuery(@"DELETE FROM [lagerposten]");
db.ExecuteNonQuery(@"DELETE FROM [produkteex]");
}
}

Expand Down

0 comments on commit f33b214

Please sign in to comment.