SlideShare a Scribd company logo
CQRS e Event Sourcing na
prática com RavenDB
Elemar Júnior
@elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
elemarjr.com
Olá, eu sou Elemar Jr
Eu sou Microsoft MVP
Eu gosto de aprender coisas novas
Eu gosto de resolver problemas
Eu gosto de escrever compiladores
Eu gosto do
Roslyn (e do
CoddeCracker)
Eu gosto de
Computação Gráfica
Eu gosto de
Heurísticas
Eu gosto de
RavenDB
CQRS e Event Sourcing na prática
com RavenDB
Mas, vamos falar de
Vamos pensar em um cenário...
Precisamos criar um um cadastro
de funcionários...
Coisa simples...
Nome, Endereço Residencial e Salário
Começamos com um protótipo
[Route("api/[controller]")]
public class EmployeesController : Controller
{
[HttpGet]
public IEnumerable<Employee> Get()
{ /* .. */ }
[HttpGet("{id}")]
public Employee Get(string id)
{ /* .. */ }
[HttpPost]
public void Post([FromBody]Employee value)
{ /* .. */ }
[HttpPut("{id}")]
public void Put(string id, [FromBody]Employee value)
{ /* .. */ }
[HttpDelete("{id}")]
public void Delete(string id)
{ /* .. */}
}
Podemos modelar
uma API...
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public Address HomeAddress { get; set; }
public decimal Salary { get; set; }
}
Definir o Modelo
[Route("api/[controller]")]
public class EmployeesController : Controller
{
[HttpGet]
public IEnumerable<Employee> Get()
{ /* .. */ }
[HttpGet("{id}")]
public Employee Get(string id)
{ /* .. */ }
[HttpPost]
public void Post([FromBody]Employee value)
{ /* .. */ }
[HttpPut("{id}")]
public void Put(string id, [FromBody]Employee value)
{ /* .. */ }
[HttpDelete("{id}")]
public void Delete(string id)
{ /* .. */}
}
public class EmployeesRepository
{
public Employee Load(string id)
{
using (var session = DocumentStoreHolder.Instance.OpenSession())
{
return session.Load<Employee>(id);
}
}
public void Save(Employee newEmployee)
{
using (var session = DocumentStoreHolder.Instance.OpenSession())
{
session.Store(newEmployee);
session.SaveChanges();
}
}
}
Implementar persistência....
Pronto!
Será que ficou bom?
Vejamos...
UI (HTML + Angular)
WebAPI
RavenDB
Presentation
Business
Persistence
Esse modelo não está anêmico?
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public Address HomeAddress { get; set; }
public decimal Salary { get; set; }
}
Cadê a linguagem ubíqua?
[Route("api/[controller]")]
public class EmployeesController : Controller
{
[HttpGet]
public IEnumerable<Employee> Get()
{ /* .. */ }
[HttpGet("{id}")]
public Employee Get(string id)
{ /* .. */ }
[HttpPost]
public void Post([FromBody]Employee value)
{ /* .. */ }
[HttpPut("{id}")]
public void Put(string id, [FromBody]Employee value)
{ /* .. */ }
[HttpDelete("{id}")]
public void Delete(string id)
{ /* .. */}
}
Será que escala?
Será que é fácil de alterar?
Vamos tentar resgatar conceitos...
ViewModel
InputModel
Modelo expressa o domínio
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Modelo expressa o domínio
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Modelo expressa o domínio
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Consolidação da Linguagem
Ubíqua
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Voltando ao protótipo...
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Consolidação da Linguagem
Ubíqua
Cadê o protótipo?
public void RaiseSalary(decimal amount)
{ /* .. */ }
Command
InputModel
Anatomia de um Comando
public sealed class UpdateEmployeeHomeAddressCommand :
EmployeeCommand
{
public Address HomeAddress { get; }
public UpdateEmployeeHomeAddressCommand(
EmployeeId id,
Address address) : base(id)
{
HomeAddress = address;
}
}
Command
InputModel
public class EmployeeCommandsHandler : IMessageHandler<RegisterEmployeeCommand>,
IMessageHandler<RaiseSalaryCommand>, IMessageHandler<ChangeHomeAddressCommand>
{
private readonly IEmployeeRepository _repository;
public EmployeeCommandsHandler(IEmployeeRepository repository)
{ _repository = repository; }
public void Handle(RegisterEmployeeCommand command)
{
var newEmployee = new Employee(command.Id, command.Name, command.InitialSalary);
_repository.Save(newEmployee);
}
public void Handle(RaiseSalaryCommand command)
{
var employee = _repository.Load(command.EmployeeId);
employee.RaiseSalary(command.Amount);
_repository.Save(employee);
}
public void Handle(ChangeHomeAddressCommand command)
{
var employee = _repository.Load(command.EmployeeId);
employee.ChangeHomeAddress(command.NewAddress);
_repository.Save(employee);
}
}
InputModel
Command
Chegamos ao Manifesto Reativo
Resolvemos comandos! O que
fazemos com consultas
Vamos lembrar...
ViewModel
Logo, seria natural...
E isso é CQRS
... mas e Event Sourcing?
Employee
RaiseSalaryCommand
SalaryRaisedEvent
Command
InputModel
Anatomia de um Evento
public class EmployeeHomeAddressChangedEvent
: VersionedEvent<Guid>
{
public Address NewAddress { get; }
public EmployeeHomeAddressChangedEvent(Address newAddress)
{
NewAddress = newAddress;
}
}
public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId>
{
public TSourceId SourceId { get; internal set; }
public DateTime When { get; private set; }
public int Version { get; internal set; }
public VersionedEvent()
{
When = DateTime.Now;
}
}
Anatomia de um Evento
public class EmployeeHomeAddressChangedEvent
: VersionedEvent<Guid>
{
public Address NewAddress { get; }
public EmployeeHomeAddressChangedEvent(Address newAddress)
{
NewAddress = newAddress;
}
}
public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId>
{
public TSourceId SourceId { get; internal set; }
public DateTime When { get; private set; }
public int Version { get; internal set; }
public VersionedEvent()
{
When = DateTime.Now;
}
}
Anatomia de um Evento
public class EmployeeHomeAddressChangedEvent
: VersionedEvent<Guid>
{
public Address NewAddress { get; }
public EmployeeHomeAddressChangedEvent(Address newAddress)
{
NewAddress = newAddress;
}
}
public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId>
{
public TSourceId SourceId { get; internal set; }
public DateTime When { get; private set; }
public int Version { get; internal set; }
public VersionedEvent()
{
When = DateTime.Now;
}
}
Stream de Eventos
EmployeeRegistered
HomeAddressUpdated
SalaryRaised
SalaryRaised
HomeAddressUpdated
SalaryRaised
Stream de Eventos
EmployeeRegistered
HomeAddressUpdated
SalaryRaised
SalaryRaised
HomeAddressUpdated
SalaryRaised
Por que não salvar?
Stream de Eventos
No RavenDB é fácil!
Stream de Eventos
No RavenDB é fácil!
... mas antes é preciso
Gerar os Eventos
Entidade/Agregado gera Eventos
public Employee(Guid id, FullName name, decimal initialSalary)
: this(id)
{
Throw.IfArgumentIsNull(name, nameof(name));
Throw.IfArgumentIsNegative(initialSalary, nameof(initialSalary));
Update(new EmployeeRegisteredEvent(name, initialSalary));
}
Entidade/Agregado gera Eventos
public void RaiseSalary(decimal amount)
{
Throw.IfArgumentIsNegative(amount, nameof(amount));
Update(new EmployeeSalaryRaisedEvent(amount));
}
Entidade/Agregado gera Eventos
public void ChangeHomeAddress(Address address)
{
Throw.IfArgumentIsNull(address, nameof(address));
Update(new EmployeeHomeAddressChangedEvent(address));
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
private Employee(Guid id) : base(id)
{
Handles<EmployeeRegisteredEvent>(OnEmployeeRegistered);
Handles<EmployeeSalaryRaisedEvent>(OnEmployeeSalaryRaised);
Handles<EmployeeHomeAddressChangedEvent>(OnEmployeeHomeAddressChanged);
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
private void OnEmployeeRegistered(EmployeeRegisteredEvent @event)
{
Name = @event.Name;
Salary = @event.InitialSalary;
}
private void OnEmployeeSalaryRaised(EmployeeSalaryRaisedEvent @event)
{
Salary += @event.Amount;
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
Stream de Eventos
EmployeeRegistered
HomeAddressUpdated
SalaryRaised
SalaryRaised
HomeAddressUpdated
SalaryRaised
Por que não salvar?
Application
(InputModel)
CommandHandler
(Command)
Entidade
(Evento)
Application
(InputModel)
CommandHandler
(Command)
Entidade
(Evento)
Application
(InputModel)
CommandHandler
(Command)
Entidade
(Evento)
Salvar um documento com
eventospublic void Save(Employee employee)
{
var head = GetHead(employee.Id);
var storedVersion = GetStoredVersionOf(head);
if (storedVersion != (employee.Version - employee.PendingEvents.Count()))
throw new InvalidOperationException("Invalid object state.");
if (head == null)
{
SaveNewEmployee(employee);
}
else
{
SaveEmployeeEvents(employee);
}
foreach (var evt in employee.PendingEvents)
Bus.RaiseEvent(evt);
}
Salvar um documento com
eventos
public JsonDocumentMetadata GetHead(Guid id)
{
string localId = $"employees/{id}";
return _store.DatabaseCommands.Head(localId);
}
public int GetStoredVersionOf(JsonDocumentMetadata
head)
{
return head
?.Metadata[EmployeeEntityVersion]
.Value<int>() ?? 0;
}
Salvar um documento com
eventospublic void Save(Employee employee)
{
var head = GetHead(employee.Id);
var storedVersion = GetStoredVersionOf(head);
if (storedVersion != (employee.Version - employee.PendingEvents.Count()))
throw new InvalidOperationException("Invalid object state.");
if (head == null)
{
SaveNewEmployee(employee);
}
else
{
SaveEmployeeEvents(employee);
}
foreach (var evt in employee.PendingEvents)
Bus.RaiseEvent(evt);
}
Salvar um documento com
eventos
private void SaveNewEmployee(Employee employee)
{
using (var session = _store.OpenSession())
{
var document = new EmployeeEvents(
employee.Id,
employee.PendingEvents
);
session.Store(document);
session.Advanced.GetMetadataFor(document)
.Add(EmployeeEntityVersion, employee.Version);
session.SaveChanges();
}
}
private void SaveEmployeeEvents(
Employee employee )
{
var patches = new List<PatchRequest>();
foreach (var evt in employee.PendingEvents)
{
patches.Add(new PatchRequest
{
Type = PatchCommandType.Add,
Name = "Events",
Value = RavenJObject.FromObject(evt, _serializer)
});
}
var localId = $"employees/{employee.Id}";
var addEmployeeEvents = new PatchCommandData()
{
Key = localId,
Patches = patches.ToArray()
};
var updateMetadata = new ScriptedPatchCommandData()
{
Key = localId,
Patch = new ScriptedPatchRequest
{
Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; "
}
};
_store.DatabaseCommands.Batch(new ICommandData[]
{
addEmployeeEvents,
updateMetadata
});
}
private void SaveEmployeeEvents(
Employee employee )
{
var patches = new List<PatchRequest>();
foreach (var evt in employee.PendingEvents)
{
patches.Add(new PatchRequest
{
Type = PatchCommandType.Add,
Name = "Events",
Value = RavenJObject.FromObject(evt, _serializer)
});
}
var localId = $"employees/{employee.Id}";
var addEmployeeEvents = new PatchCommandData()
{
Key = localId,
Patches = patches.ToArray()
};
var updateMetadata = new ScriptedPatchCommandData()
{
Key = localId,
Patch = new ScriptedPatchRequest
{
Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; "
}
};
_store.DatabaseCommands.Batch(new ICommandData[]
{
addEmployeeEvents,
updateMetadata
});
}
private void SaveEmployeeEvents(
Employee employee )
{
var patches = new List<PatchRequest>();
foreach (var evt in employee.PendingEvents)
{
patches.Add(new PatchRequest
{
Type = PatchCommandType.Add,
Name = "Events",
Value = RavenJObject.FromObject(evt, _serializer)
});
}
var localId = $"employees/{employee.Id}";
var addEmployeeEvents = new PatchCommandData()
{
Key = localId,
Patches = patches.ToArray()
};
var updateMetadata = new ScriptedPatchCommandData()
{
Key = localId,
Patch = new ScriptedPatchRequest
{
Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; "
}
};
_store.DatabaseCommands.Batch(new ICommandData[]
{
addEmployeeEvents,
updateMetadata
});
}
Salvar um documento com
eventospublic void Save(Employee employee)
{
var head = GetHead(employee.Id);
var storedVersion = GetStoredVersionOf(head);
if (storedVersion != (employee.Version - employee.PendingEvents.Count()))
throw new InvalidOperationException("Invalid object state.");
if (head == null)
{
SaveNewEmployee(employee);
}
else
{
SaveEmployeeEvents(employee);
}
foreach (var evt in employee.PendingEvents)
Bus.RaiseEvent(evt);
}
Carregar um documento com
eventos
public Employee Load(Guid id)
{
EmployeeEvents data;
using (var session = _store.OpenSession())
{
data = session.Load<EmployeeEvents>(id);
}
return new Employee(id, data.Events);
}
public Employee(Guid id,
IEnumerable<IVersionedEvent<Guid>> history)
: this(id)
{
LoadFrom(history);
}
Carregar um documento com
eventos
protected void LoadFrom(IEnumerable<IVersionedEvent<TId>> pastEvents)
{
foreach (var e in pastEvents)
{
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
}
}
elemarjr.com
@elemarjr
linkedin.com/in/elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
Mantenha contato!
CQRS e Event Sourcing na
prática com RavenDB
Elemar Júnior
@elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
elemarjr.com

More Related Content

What's hot

Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
Alina Vilk
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambaryoyomay93
 
Multi client
Multi clientMulti client
Multi clientAisy Cuyy
 
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsTypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
Alfonso Peletier
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2Technopark
 
Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)Rara Ariesta
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
Michael Girouard
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
Arturo Herrero
 
Multi client
Multi clientMulti client
Multi clientganteng8
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
Peter Gfader
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
Fiyaz Hasan
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
The Software House
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
Alonso Torres
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
The Software House
 
Building High Performance Web Applications and Sites
Building High Performance Web Applications and SitesBuilding High Performance Web Applications and Sites
Building High Performance Web Applications and Sites
goodfriday
 
JNI - Java & C in the same project
JNI - Java & C in the same projectJNI - Java & C in the same project
JNI - Java & C in the same project
Karol Wrótniak
 
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)James Clause
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! aleks-f
 
LINQ Internals - STLDODN
LINQ Internals - STLDODNLINQ Internals - STLDODN
LINQ Internals - STLDODN
Keith Dahlby
 

What's hot (19)

Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambar
 
Multi client
Multi clientMulti client
Multi client
 
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsTypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
 
Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Multi client
Multi clientMulti client
Multi client
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
Building High Performance Web Applications and Sites
Building High Performance Web Applications and SitesBuilding High Performance Web Applications and Sites
Building High Performance Web Applications and Sites
 
JNI - Java & C in the same project
JNI - Java & C in the same projectJNI - Java & C in the same project
JNI - Java & C in the same project
 
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! 
 
LINQ Internals - STLDODN
LINQ Internals - STLDODNLINQ Internals - STLDODN
LINQ Internals - STLDODN
 

Viewers also liked

TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarial
tdc-globalcode
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarial
tdc-globalcode
 
TDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net CoreTDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net Core
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 
TDC2016SP - Fillas com php
TDC2016SP - Fillas com phpTDC2016SP - Fillas com php
TDC2016SP - Fillas com php
tdc-globalcode
 
TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0
tdc-globalcode
 
TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?
tdc-globalcode
 
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red HatTDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
tdc-globalcode
 
TDC2016SP - Internet das Coisas
TDC2016SP - Internet das CoisasTDC2016SP - Internet das Coisas
TDC2016SP - Internet das Coisas
tdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
tdc-globalcode
 

Viewers also liked (20)

TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarial
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarial
 
TDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net CoreTDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net Core
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Fillas com php
TDC2016SP - Fillas com phpTDC2016SP - Fillas com php
TDC2016SP - Fillas com php
 
TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0
 
TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?
 
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red HatTDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
 
TDC2016SP - Internet das Coisas
TDC2016SP - Internet das CoisasTDC2016SP - Internet das Coisas
TDC2016SP - Internet das Coisas
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 

Similar to TDC2016SP - Trilha .NET

Implementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDBImplementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDB
Oren Eini
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
.NET Conf UY
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
Daniel Wellman
 
VRaptor 4 - JavaOne
VRaptor 4 - JavaOneVRaptor 4 - JavaOne
VRaptor 4 - JavaOne
Rodrigo Turini
 
Web2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API RESTWeb2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API REST
Nicolas Faugout
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
OOP Lab Report.docx
OOP Lab Report.docxOOP Lab Report.docx
OOP Lab Report.docx
ArafatSahinAfridi
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design Patterns
Stefano Fago
 
Best of build 2021 - C# 10 & .NET 6
Best of build 2021 -  C# 10 & .NET 6Best of build 2021 -  C# 10 & .NET 6
Best of build 2021 - C# 10 & .NET 6
Moaid Hathot
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji
Jakub Marchwicki
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015
Tomasz Dziuda
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
Maarten Balliauw
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
Dhaval Dalal
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good codeGiordano Scalzo
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
Ali Parmaksiz
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
Mostafa Amer
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
Jonathan Wage
 

Similar to TDC2016SP - Trilha .NET (20)

Implementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDBImplementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDB
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
VRaptor 4 - JavaOne
VRaptor 4 - JavaOneVRaptor 4 - JavaOne
VRaptor 4 - JavaOne
 
Web2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API RESTWeb2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API REST
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
OOP Lab Report.docx
OOP Lab Report.docxOOP Lab Report.docx
OOP Lab Report.docx
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design Patterns
 
CSharp v1.0.2
CSharp v1.0.2CSharp v1.0.2
CSharp v1.0.2
 
Best of build 2021 - C# 10 & .NET 6
Best of build 2021 -  C# 10 & .NET 6Best of build 2021 -  C# 10 & .NET 6
Best of build 2021 - C# 10 & .NET 6
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good code
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 

More from tdc-globalcode

TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidadeTDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
tdc-globalcode
 
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
tdc-globalcode
 
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de SucessoTDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
tdc-globalcode
 
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPATDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
tdc-globalcode
 
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVinoTDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
tdc-globalcode
 
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
tdc-globalcode
 
TDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devicesTDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devices
tdc-globalcode
 
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca PublicaTrilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
tdc-globalcode
 
Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#
tdc-globalcode
 
TDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case EasylocusTDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case Easylocus
tdc-globalcode
 
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
tdc-globalcode
 
TDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em GolangTDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em Golang
tdc-globalcode
 
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QATDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
tdc-globalcode
 
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendenciaTDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
tdc-globalcode
 
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR ServiceTDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
tdc-globalcode
 
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NETTDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
tdc-globalcode
 
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
tdc-globalcode
 
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
tdc-globalcode
 
TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#
tdc-globalcode
 
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net CoreTDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
tdc-globalcode
 

More from tdc-globalcode (20)

TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidadeTDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
 
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
 
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de SucessoTDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
 
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPATDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
 
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVinoTDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
 
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
 
TDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devicesTDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devices
 
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca PublicaTrilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
 
Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#
 
TDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case EasylocusTDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case Easylocus
 
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
 
TDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em GolangTDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em Golang
 
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QATDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
 
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendenciaTDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
 
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR ServiceTDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
 
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NETTDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
 
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
 
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
 
TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#
 
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net CoreTDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
 

Recently uploaded

Overview on Edible Vaccine: Pros & Cons with Mechanism
Overview on Edible Vaccine: Pros & Cons with MechanismOverview on Edible Vaccine: Pros & Cons with Mechanism
Overview on Edible Vaccine: Pros & Cons with Mechanism
DeeptiGupta154
 
BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...
BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...
BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...
Nguyen Thanh Tu Collection
 
STRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBC
STRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBCSTRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBC
STRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBC
kimdan468
 
Digital Artifact 1 - 10VCD Environments Unit
Digital Artifact 1 - 10VCD Environments UnitDigital Artifact 1 - 10VCD Environments Unit
Digital Artifact 1 - 10VCD Environments Unit
chanes7
 
Chapter 4 - Islamic Financial Institutions in Malaysia.pptx
Chapter 4 - Islamic Financial Institutions in Malaysia.pptxChapter 4 - Islamic Financial Institutions in Malaysia.pptx
Chapter 4 - Islamic Financial Institutions in Malaysia.pptx
Mohd Adib Abd Muin, Senior Lecturer at Universiti Utara Malaysia
 
Digital Artifact 2 - Investigating Pavilion Designs
Digital Artifact 2 - Investigating Pavilion DesignsDigital Artifact 2 - Investigating Pavilion Designs
Digital Artifact 2 - Investigating Pavilion Designs
chanes7
 
The Diamonds of 2023-2024 in the IGRA collection
The Diamonds of 2023-2024 in the IGRA collectionThe Diamonds of 2023-2024 in the IGRA collection
The Diamonds of 2023-2024 in the IGRA collection
Israel Genealogy Research Association
 
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama UniversityNatural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
Akanksha trivedi rama nursing college kanpur.
 
Unit 8 - Information and Communication Technology (Paper I).pdf
Unit 8 - Information and Communication Technology (Paper I).pdfUnit 8 - Information and Communication Technology (Paper I).pdf
Unit 8 - Information and Communication Technology (Paper I).pdf
Thiyagu K
 
The approach at University of Liverpool.pptx
The approach at University of Liverpool.pptxThe approach at University of Liverpool.pptx
The approach at University of Liverpool.pptx
Jisc
 
special B.ed 2nd year old paper_20240531.pdf
special B.ed 2nd year old paper_20240531.pdfspecial B.ed 2nd year old paper_20240531.pdf
special B.ed 2nd year old paper_20240531.pdf
Special education needs
 
June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...
June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...
June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...
Levi Shapiro
 
Acetabularia Information For Class 9 .docx
Acetabularia Information For Class 9  .docxAcetabularia Information For Class 9  .docx
Acetabularia Information For Class 9 .docx
vaibhavrinwa19
 
Pride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School DistrictPride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School District
David Douglas School District
 
Unit 2- Research Aptitude (UGC NET Paper I).pdf
Unit 2- Research Aptitude (UGC NET Paper I).pdfUnit 2- Research Aptitude (UGC NET Paper I).pdf
Unit 2- Research Aptitude (UGC NET Paper I).pdf
Thiyagu K
 
Azure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHatAzure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHat
Scholarhat
 
Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...
Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...
Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...
Dr. Vinod Kumar Kanvaria
 
Biological Screening of Herbal Drugs in detailed.
Biological Screening of Herbal Drugs in detailed.Biological Screening of Herbal Drugs in detailed.
Biological Screening of Herbal Drugs in detailed.
Ashokrao Mane college of Pharmacy Peth-Vadgaon
 
How libraries can support authors with open access requirements for UKRI fund...
How libraries can support authors with open access requirements for UKRI fund...How libraries can support authors with open access requirements for UKRI fund...
How libraries can support authors with open access requirements for UKRI fund...
Jisc
 
The basics of sentences session 5pptx.pptx
The basics of sentences session 5pptx.pptxThe basics of sentences session 5pptx.pptx
The basics of sentences session 5pptx.pptx
heathfieldcps1
 

Recently uploaded (20)

Overview on Edible Vaccine: Pros & Cons with Mechanism
Overview on Edible Vaccine: Pros & Cons with MechanismOverview on Edible Vaccine: Pros & Cons with Mechanism
Overview on Edible Vaccine: Pros & Cons with Mechanism
 
BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...
BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...
BÀI TẬP BỔ TRỢ TIẾNG ANH GLOBAL SUCCESS LỚP 3 - CẢ NĂM (CÓ FILE NGHE VÀ ĐÁP Á...
 
STRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBC
STRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBCSTRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBC
STRAND 3 HYGIENIC PRACTICES.pptx GRADE 7 CBC
 
Digital Artifact 1 - 10VCD Environments Unit
Digital Artifact 1 - 10VCD Environments UnitDigital Artifact 1 - 10VCD Environments Unit
Digital Artifact 1 - 10VCD Environments Unit
 
Chapter 4 - Islamic Financial Institutions in Malaysia.pptx
Chapter 4 - Islamic Financial Institutions in Malaysia.pptxChapter 4 - Islamic Financial Institutions in Malaysia.pptx
Chapter 4 - Islamic Financial Institutions in Malaysia.pptx
 
Digital Artifact 2 - Investigating Pavilion Designs
Digital Artifact 2 - Investigating Pavilion DesignsDigital Artifact 2 - Investigating Pavilion Designs
Digital Artifact 2 - Investigating Pavilion Designs
 
The Diamonds of 2023-2024 in the IGRA collection
The Diamonds of 2023-2024 in the IGRA collectionThe Diamonds of 2023-2024 in the IGRA collection
The Diamonds of 2023-2024 in the IGRA collection
 
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama UniversityNatural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
 
Unit 8 - Information and Communication Technology (Paper I).pdf
Unit 8 - Information and Communication Technology (Paper I).pdfUnit 8 - Information and Communication Technology (Paper I).pdf
Unit 8 - Information and Communication Technology (Paper I).pdf
 
The approach at University of Liverpool.pptx
The approach at University of Liverpool.pptxThe approach at University of Liverpool.pptx
The approach at University of Liverpool.pptx
 
special B.ed 2nd year old paper_20240531.pdf
special B.ed 2nd year old paper_20240531.pdfspecial B.ed 2nd year old paper_20240531.pdf
special B.ed 2nd year old paper_20240531.pdf
 
June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...
June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...
June 3, 2024 Anti-Semitism Letter Sent to MIT President Kornbluth and MIT Cor...
 
Acetabularia Information For Class 9 .docx
Acetabularia Information For Class 9  .docxAcetabularia Information For Class 9  .docx
Acetabularia Information For Class 9 .docx
 
Pride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School DistrictPride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School District
 
Unit 2- Research Aptitude (UGC NET Paper I).pdf
Unit 2- Research Aptitude (UGC NET Paper I).pdfUnit 2- Research Aptitude (UGC NET Paper I).pdf
Unit 2- Research Aptitude (UGC NET Paper I).pdf
 
Azure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHatAzure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHat
 
Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...
Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...
Exploiting Artificial Intelligence for Empowering Researchers and Faculty, In...
 
Biological Screening of Herbal Drugs in detailed.
Biological Screening of Herbal Drugs in detailed.Biological Screening of Herbal Drugs in detailed.
Biological Screening of Herbal Drugs in detailed.
 
How libraries can support authors with open access requirements for UKRI fund...
How libraries can support authors with open access requirements for UKRI fund...How libraries can support authors with open access requirements for UKRI fund...
How libraries can support authors with open access requirements for UKRI fund...
 
The basics of sentences session 5pptx.pptx
The basics of sentences session 5pptx.pptxThe basics of sentences session 5pptx.pptx
The basics of sentences session 5pptx.pptx
 

TDC2016SP - Trilha .NET

  • 1. CQRS e Event Sourcing na prática com RavenDB Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com
  • 2. Olá, eu sou Elemar Jr
  • 4. Eu gosto de aprender coisas novas
  • 5. Eu gosto de resolver problemas
  • 6. Eu gosto de escrever compiladores
  • 7. Eu gosto do Roslyn (e do CoddeCracker)
  • 11. CQRS e Event Sourcing na prática com RavenDB Mas, vamos falar de
  • 12. Vamos pensar em um cenário...
  • 13. Precisamos criar um um cadastro de funcionários...
  • 14. Coisa simples... Nome, Endereço Residencial e Salário
  • 15. Começamos com um protótipo
  • 16. [Route("api/[controller]")] public class EmployeesController : Controller { [HttpGet] public IEnumerable<Employee> Get() { /* .. */ } [HttpGet("{id}")] public Employee Get(string id) { /* .. */ } [HttpPost] public void Post([FromBody]Employee value) { /* .. */ } [HttpPut("{id}")] public void Put(string id, [FromBody]Employee value) { /* .. */ } [HttpDelete("{id}")] public void Delete(string id) { /* .. */} } Podemos modelar uma API...
  • 17. public class Employee { public string Id { get; set; } public string Name { get; set; } public Address HomeAddress { get; set; } public decimal Salary { get; set; } } Definir o Modelo [Route("api/[controller]")] public class EmployeesController : Controller { [HttpGet] public IEnumerable<Employee> Get() { /* .. */ } [HttpGet("{id}")] public Employee Get(string id) { /* .. */ } [HttpPost] public void Post([FromBody]Employee value) { /* .. */ } [HttpPut("{id}")] public void Put(string id, [FromBody]Employee value) { /* .. */ } [HttpDelete("{id}")] public void Delete(string id) { /* .. */} }
  • 18. public class EmployeesRepository { public Employee Load(string id) { using (var session = DocumentStoreHolder.Instance.OpenSession()) { return session.Load<Employee>(id); } } public void Save(Employee newEmployee) { using (var session = DocumentStoreHolder.Instance.OpenSession()) { session.Store(newEmployee); session.SaveChanges(); } } } Implementar persistência....
  • 22. UI (HTML + Angular) WebAPI RavenDB Presentation Business Persistence
  • 23. Esse modelo não está anêmico? public class Employee { public string Id { get; set; } public string Name { get; set; } public Address HomeAddress { get; set; } public decimal Salary { get; set; } }
  • 24. Cadê a linguagem ubíqua? [Route("api/[controller]")] public class EmployeesController : Controller { [HttpGet] public IEnumerable<Employee> Get() { /* .. */ } [HttpGet("{id}")] public Employee Get(string id) { /* .. */ } [HttpPost] public void Post([FromBody]Employee value) { /* .. */ } [HttpPut("{id}")] public void Put(string id, [FromBody]Employee value) { /* .. */ } [HttpDelete("{id}")] public void Delete(string id) { /* .. */} }
  • 26. Será que é fácil de alterar?
  • 27. Vamos tentar resgatar conceitos...
  • 28.
  • 29.
  • 30.
  • 32.
  • 33. Modelo expressa o domínio public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 34. Modelo expressa o domínio public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 35. Modelo expressa o domínio public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 36. Consolidação da Linguagem Ubíqua public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 37. Voltando ao protótipo... public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ }
  • 38. public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } } Consolidação da Linguagem Ubíqua
  • 39. Cadê o protótipo? public void RaiseSalary(decimal amount) { /* .. */ }
  • 41. Anatomia de um Comando public sealed class UpdateEmployeeHomeAddressCommand : EmployeeCommand { public Address HomeAddress { get; } public UpdateEmployeeHomeAddressCommand( EmployeeId id, Address address) : base(id) { HomeAddress = address; } }
  • 43. public class EmployeeCommandsHandler : IMessageHandler<RegisterEmployeeCommand>, IMessageHandler<RaiseSalaryCommand>, IMessageHandler<ChangeHomeAddressCommand> { private readonly IEmployeeRepository _repository; public EmployeeCommandsHandler(IEmployeeRepository repository) { _repository = repository; } public void Handle(RegisterEmployeeCommand command) { var newEmployee = new Employee(command.Id, command.Name, command.InitialSalary); _repository.Save(newEmployee); } public void Handle(RaiseSalaryCommand command) { var employee = _repository.Load(command.EmployeeId); employee.RaiseSalary(command.Amount); _repository.Save(employee); } public void Handle(ChangeHomeAddressCommand command) { var employee = _repository.Load(command.EmployeeId); employee.ChangeHomeAddress(command.NewAddress); _repository.Save(employee); } }
  • 44.
  • 45.
  • 48. Resolvemos comandos! O que fazemos com consultas
  • 52.
  • 53.
  • 54. E isso é CQRS
  • 55. ... mas e Event Sourcing?
  • 58. Anatomia de um Evento public class EmployeeHomeAddressChangedEvent : VersionedEvent<Guid> { public Address NewAddress { get; } public EmployeeHomeAddressChangedEvent(Address newAddress) { NewAddress = newAddress; } } public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId> { public TSourceId SourceId { get; internal set; } public DateTime When { get; private set; } public int Version { get; internal set; } public VersionedEvent() { When = DateTime.Now; } }
  • 59. Anatomia de um Evento public class EmployeeHomeAddressChangedEvent : VersionedEvent<Guid> { public Address NewAddress { get; } public EmployeeHomeAddressChangedEvent(Address newAddress) { NewAddress = newAddress; } } public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId> { public TSourceId SourceId { get; internal set; } public DateTime When { get; private set; } public int Version { get; internal set; } public VersionedEvent() { When = DateTime.Now; } }
  • 60. Anatomia de um Evento public class EmployeeHomeAddressChangedEvent : VersionedEvent<Guid> { public Address NewAddress { get; } public EmployeeHomeAddressChangedEvent(Address newAddress) { NewAddress = newAddress; } } public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId> { public TSourceId SourceId { get; internal set; } public DateTime When { get; private set; } public int Version { get; internal set; } public VersionedEvent() { When = DateTime.Now; } }
  • 63. Stream de Eventos No RavenDB é fácil!
  • 64. Stream de Eventos No RavenDB é fácil!
  • 65. ... mas antes é preciso Gerar os Eventos
  • 66. Entidade/Agregado gera Eventos public Employee(Guid id, FullName name, decimal initialSalary) : this(id) { Throw.IfArgumentIsNull(name, nameof(name)); Throw.IfArgumentIsNegative(initialSalary, nameof(initialSalary)); Update(new EmployeeRegisteredEvent(name, initialSalary)); }
  • 67. Entidade/Agregado gera Eventos public void RaiseSalary(decimal amount) { Throw.IfArgumentIsNegative(amount, nameof(amount)); Update(new EmployeeSalaryRaisedEvent(amount)); }
  • 68. Entidade/Agregado gera Eventos public void ChangeHomeAddress(Address address) { Throw.IfArgumentIsNull(address, nameof(address)); Update(new EmployeeHomeAddressChangedEvent(address)); }
  • 69. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); }
  • 70. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); } private Employee(Guid id) : base(id) { Handles<EmployeeRegisteredEvent>(OnEmployeeRegistered); Handles<EmployeeSalaryRaisedEvent>(OnEmployeeSalaryRaised); Handles<EmployeeHomeAddressChangedEvent>(OnEmployeeHomeAddressChanged); }
  • 71. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); } private void OnEmployeeRegistered(EmployeeRegisteredEvent @event) { Name = @event.Name; Salary = @event.InitialSalary; } private void OnEmployeeSalaryRaised(EmployeeSalaryRaisedEvent @event) { Salary += @event.Amount; }
  • 72. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); }
  • 77. Salvar um documento com eventospublic void Save(Employee employee) { var head = GetHead(employee.Id); var storedVersion = GetStoredVersionOf(head); if (storedVersion != (employee.Version - employee.PendingEvents.Count())) throw new InvalidOperationException("Invalid object state."); if (head == null) { SaveNewEmployee(employee); } else { SaveEmployeeEvents(employee); } foreach (var evt in employee.PendingEvents) Bus.RaiseEvent(evt); }
  • 78. Salvar um documento com eventos public JsonDocumentMetadata GetHead(Guid id) { string localId = $"employees/{id}"; return _store.DatabaseCommands.Head(localId); } public int GetStoredVersionOf(JsonDocumentMetadata head) { return head ?.Metadata[EmployeeEntityVersion] .Value<int>() ?? 0; }
  • 79. Salvar um documento com eventospublic void Save(Employee employee) { var head = GetHead(employee.Id); var storedVersion = GetStoredVersionOf(head); if (storedVersion != (employee.Version - employee.PendingEvents.Count())) throw new InvalidOperationException("Invalid object state."); if (head == null) { SaveNewEmployee(employee); } else { SaveEmployeeEvents(employee); } foreach (var evt in employee.PendingEvents) Bus.RaiseEvent(evt); }
  • 80. Salvar um documento com eventos private void SaveNewEmployee(Employee employee) { using (var session = _store.OpenSession()) { var document = new EmployeeEvents( employee.Id, employee.PendingEvents ); session.Store(document); session.Advanced.GetMetadataFor(document) .Add(EmployeeEntityVersion, employee.Version); session.SaveChanges(); } }
  • 81. private void SaveEmployeeEvents( Employee employee ) { var patches = new List<PatchRequest>(); foreach (var evt in employee.PendingEvents) { patches.Add(new PatchRequest { Type = PatchCommandType.Add, Name = "Events", Value = RavenJObject.FromObject(evt, _serializer) }); } var localId = $"employees/{employee.Id}"; var addEmployeeEvents = new PatchCommandData() { Key = localId, Patches = patches.ToArray() }; var updateMetadata = new ScriptedPatchCommandData() { Key = localId, Patch = new ScriptedPatchRequest { Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; " } }; _store.DatabaseCommands.Batch(new ICommandData[] { addEmployeeEvents, updateMetadata }); }
  • 82. private void SaveEmployeeEvents( Employee employee ) { var patches = new List<PatchRequest>(); foreach (var evt in employee.PendingEvents) { patches.Add(new PatchRequest { Type = PatchCommandType.Add, Name = "Events", Value = RavenJObject.FromObject(evt, _serializer) }); } var localId = $"employees/{employee.Id}"; var addEmployeeEvents = new PatchCommandData() { Key = localId, Patches = patches.ToArray() }; var updateMetadata = new ScriptedPatchCommandData() { Key = localId, Patch = new ScriptedPatchRequest { Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; " } }; _store.DatabaseCommands.Batch(new ICommandData[] { addEmployeeEvents, updateMetadata }); }
  • 83. private void SaveEmployeeEvents( Employee employee ) { var patches = new List<PatchRequest>(); foreach (var evt in employee.PendingEvents) { patches.Add(new PatchRequest { Type = PatchCommandType.Add, Name = "Events", Value = RavenJObject.FromObject(evt, _serializer) }); } var localId = $"employees/{employee.Id}"; var addEmployeeEvents = new PatchCommandData() { Key = localId, Patches = patches.ToArray() }; var updateMetadata = new ScriptedPatchCommandData() { Key = localId, Patch = new ScriptedPatchRequest { Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; " } }; _store.DatabaseCommands.Batch(new ICommandData[] { addEmployeeEvents, updateMetadata }); }
  • 84. Salvar um documento com eventospublic void Save(Employee employee) { var head = GetHead(employee.Id); var storedVersion = GetStoredVersionOf(head); if (storedVersion != (employee.Version - employee.PendingEvents.Count())) throw new InvalidOperationException("Invalid object state."); if (head == null) { SaveNewEmployee(employee); } else { SaveEmployeeEvents(employee); } foreach (var evt in employee.PendingEvents) Bus.RaiseEvent(evt); }
  • 85. Carregar um documento com eventos public Employee Load(Guid id) { EmployeeEvents data; using (var session = _store.OpenSession()) { data = session.Load<EmployeeEvents>(id); } return new Employee(id, data.Events); } public Employee(Guid id, IEnumerable<IVersionedEvent<Guid>> history) : this(id) { LoadFrom(history); }
  • 86. Carregar um documento com eventos protected void LoadFrom(IEnumerable<IVersionedEvent<TId>> pastEvents) { foreach (var e in pastEvents) { _handlers[e.GetType()].Invoke(e); Version = e.Version; } }
  • 87.
  • 89. CQRS e Event Sourcing na prática com RavenDB Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com