I am trying to implement a pure event sourced service to see where I will get problems. Now I found a problem that I can not solve so far, so I would like to open a discussion about it.
Given the following aggregate:
class User
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public void Apply(UserNameChangedEvent domainEvent)
{
Name = domainEvent.NewName;
}
public void Apply(UserCreatedEvent domainEvent)
{
Name = domainEvent.Name;
Id = domainEvent.Id;
}
}
and those Domain Events
class UserCreatedEvent
{
public string NewName { get; }
public Guid Id { get; }
public UserCreatedEvent(string newName, Guid id)
{
NewName = newName;
Id = id;
}
}
class UserNameChangedEvent
{
public string NewName { get; }
public UserNameChangedEvent(string newName)
{
NewName = newName;
}
}
Lets say I create a user and change its name to "Peter" afterwards, then I have a UserCretedEvent and a UserChangedNameEvent persisted in my EventStore. Now the business says that changing a name is no longer possible and therefore I would remove the class UserChangedNameEvent and the function that handles it. But now I have the problem that I can not recreate the aggregate in its correct state, which would be with the name "Peter".
Of course I could start hacking around and mark the function and class as deprecated, so I could keep using it, but I might end up with a lot of event classes afterwards and this will be a nightmare to keep track of. I also heard you might create a new event that persists the change in the domain, but that also seems very hacky to me and not a very good style, as this is no domain event in my point of view.
So the question is, how do I deal the best with changes like this?
edit: just to clarify: I do not want to delete any event, just the class and the function where I use it, as the requirement is different now.
THE resource for questions related to changes in event schemas is Versioning in an Event Sourced System, by Greg Young.
So the question is, how do I deal the best with changes like this?
It depends on the real problem that you are trying to solve.
If the requirement is that users aren't allowed to change their names in the future, then you take away the logic in the domain model that creates new UserNameChangedEvents, but leave behind the correct processing where the events do appear.
If the requirement is that changes to user names should be ignored, then you also take the Apply(UserNameChanged) handler and turn it into a NoOp, just as you would for any other unrecognized event.
If the requirement is that information about name changes should be destroyed, then you migrate your event store to a new schema, that no longer includes the UserNameChanged event.
It may help to think through how you would solve the problem if you were storing your state in an RDBMS: is it enough to ignore the User Name column? do you need to delete the column? Do you need to (somehow) restore value in a column to a previously written value?
Knowing the problem in a traditional database that is analogous to the problem you want to solve in the event store should help identify the appropriate solution.
Also: pay attention to whether or not your domain model is the system of record for the data that needs changed, or if instead you are caching a representation of information published by a different authority.
Events captured facts about the system. If User name was changed at some point, it is a fact. Future business rule changes cannot affect past facts.
So you should not remove UserNameChanged events, and all associated handlers, events are there, and you should not rewrite past history.
In CQRS app, events are generated by command handlers. So this is a place where you specify business requirements. "Now the business says that changing a name is no longer possible" means that ChangeName command is no longer available: you can simply remove it, or just throw an error saying that you cannot change names anymore.
Related
I am trying to create a system that requires an admin to approve a modification to an entity before being published. This system is a REST API with authentication/authorization already working, so that part is not important. Let's assume we have a model depicting an article, with a title and a body. A normal user is allowed to modify all the fields, but before the article is published, it must be approved by an admin. But while the article is in ``approval mode'', the old version of the article must be accessible by the REST API so to at least have a version that works (and the API does not return a 404).
The requirements are:
I am using Spring Data and PostgreSQL so the one that gives me less headaches while integrating it is the one I am going with
The less tinkering with weird checks, the better
If possible, it should be modifiable to be used with other entities
If possible, I would like to keep the old versions and who modified them. Non essential but would be nice
I have two different ideas, but I am not sure which one is the best one:
Create an abstract parent class, and then extend it with an approved and a non-approved version. Then, when the modification is approved the entity is transformed into an approved one and the API will return the new version:
public abstract class Article {}
public class ApprovedArticle extends Article {}
public class ModifiedArticle extends Article {}
Create a separate table where the modified entities are stored, and restrict the view to be admin only. In this case I would isolate the two types and make it easier when fetching info. But I am losing the ``history'' this way and I need to fetch from two different locations.
Simple boolean flag: this is my last resort, and I would love to avoid it!
Is there a better way or should I use one of the outlined examples?
Thanks!
Look into spring Auditing.
https://www.baeldung.com/database-auditing-jpa
So there is an idea:
for each table you have a history table, each history table has REVTYPE( “0” for adding, “1” for updating, “2” for removing an entity) and REV(change number) columns.
Besides these, you need an extra table named REVINFO will be generated by default, to have user details you need to extend default DefaultRevisionEntity class.
#Entity
#RevisionEntity(YOURRevisionListener.class)
#Table(name = "your_audit_info")
#AttributeOverrides(
{#AttributeOverride(name = "timestamp", column = #Column(name = "REVTSTMP")),
#AttributeOverride(name = "id", column = #Column(name = "REV"))})
public class AuditInfo extends DefaultRevisionEntity
{
private static final long serialVersionUID = 8458400378132903089L;
#Column(name = "UpdateUser", nullable = false)
private String userName;
public String getUserName()
{
return userName;
}
public void setUserName(
final String userName)
{
this.userName = userName;
}
}
with audit set up, you get user details if the change approved by admin then compare revisions number when the operation started and operation approved to avoid overwriting by others.
#PrePersist
public void onPrePersist() {
audit("INSERT");
}
#PreUpdate
public void onPreUpdate() {
audit("UPDATE");
}
#PreRemove
public void onPreRemove() {
audit("DELETE");
}
I know it is a very high-level approach, but it can work in your case
The question could also look like "Why is my initialization code of object in server not working?".
For example,
public class Order
{
public int Id { get; set; }
public int Quantity { get; set; }
public Order()
{
Quantity = 10;
}
}
From debugger, I can see the contructor is called and Quantity is set, however, it is not taking effect. I have to set Quantity on client side after the entity is created to make it work.
Is there a way to make the initialization on server work? By the way, my project is in Angular/Breeze/EF.
UPDATE: As I dig a little further, I believe, this is the general "issue" with Breeze that the server side change must be added to so-called entityInfo.OriginalValueMap, otherwise, its change is not saved. If true, how can work around this limitation because I have a lot default values I'd like to set on server?
This is how I create my entity:
var manager = new breeze.EntityManager("breeze/breeze");
manager.enableSaveQueuing(true);
function _createEntity(entityName) {
return manager.createEntity(entityName);
}
Setting any initialization code on the server in the model constructor won't work simply because the JavaScript client doesn't know anything about the C# constructor code on the server.
The DefaultValueAttribute is only honored when you're constructing a Model-First metadata. It is unfortunately ignored by EF when constructing a Code-First model metadata.
I suggest that you see Breeze - Create Entity on Server side for how another user solves a similar situation by creating a "create Endpoint" on the server that basically returns a new entity with default values set.
You don't have to create a constructor to set default values.
Just add the default value data annotation to any property you wish to set its default value:
[DefaultValue(10)]
public int Quantity { get; set; }
Also, consider not to initialize the Quantity when creating an entity at the client side.
I have a web api project that I'm building on an N-Tier system. Without causing too many changes to the overall system, I will not be touching the data server that has access to the database. Instead, I'm using .NET remoting to create a tcp channel that will allow me to send requests to the data server, which will then query the database and send back a response object.
On my application, I would like to use entity framework to create my datacontexts (unit of work), then create a repository pattern that interfaces with those contexts, which will be called by the web api project that I created.
However, I'm having problems with entity framework as it requires me to have a connection with the database. Is there anyway I can create a full entity framework project without any sqlconnections to the database? I just need dbcontexts, which I will be mapping my response objects and I figure that EF would do what I needed (ie help with design, and team collabs, and provide a nice graphical designer); but it throws an error insisting that I need a connection string.
I've been searching high and low for tutorials where a database is not needed, nor any sql connection string (this means no localdb either).
Okay as promised, I have 3 solutions for this. I personally went with #3.
Note: Whenever there is a repository pattern present, and "datacontext" is used, this is interpreted as your UnitOfWork.
Solution 1: Create singletons to represent your datacontext.
http://www.breezejs.com/samples/nodb
I found this idea after going to BreezeJS.com's website and checked out their samples. They have a sample called NoDb, which allows them to create a singleton, which can create an item and a list of items, and a method to populate the datacontext. You create singletons that would lock a space in memory to prevent any kind of thread conflicts. Here is a tid bit of the code:
//generates singleton
public class TodoContext
{
static TodoContext{ }
private TodoContext() { }
public static TodoContext Instance
{
get
{
if (!__instance._initialized)
{
__instance.PopulateWithSampleData();
__instance._initialized = true;
}
return __instance;
}
}
public void PopulateWithSampleData()
{
var newList = new TodoItem { Title = "Before work"};
AddTodoList(newList);
var listId = newList.TodoListId;
var newItem = new TodoItem {
TodoListId = listId, Title = "Make coffee", IsDone = false };
AddTodoItem(newItem);
newItem = new TodoItem {
TodoListId = listId, Title = "Turn heater off", IsDone = false };
AddTodoItem(newItem);
}
//SaveChanges(), SaveTodoList(), AddTodoItem, etc.
{ ... }
private static readonly Object __lock = new Object();
private static readonly TodoContext __instance = new TodoContext();
private bool _initialized;
private readonly List<TodoItem> _todoLists = new List<TodoItem>();
private readonly List<KeyMapping> _keyMappings = new List<KeyMapping>();
}
There's a repository included which directs how to save the context and what needs to be done before the context is saved. It also allows the list of items to be queryable.
Problem I had with this:
I felt like there was higher maintenance when creating new datacontexts. If I have StateContext, CityContext, CountryContext, the overhead of creating them would be too great. I'd have problems trying to wrap my head around relating them to each other as well. Plus I'm not too sure how many people out there who agree with using singletons. I've read articles that we should avoid singletons at all costs. I'm more concerns about anyone who'd be reading this much code.
Solution 2: Override the Seed() for DropCreateDatabaseAlways
http://www.itorian.com/2012/10/entity-frameworks-database-seed-method.html
For this trick, you have to create a class called SampleDatastoreInitializer that inherits from System.Data.Entity.DropCreateDatabaseAlways where T is the datacontext, which has a reference to a collection of your POCO model.
public class State
{
[Key()]
public string Abbr{ get; set; }
public string Name{ get; set; }
}
public class StateContext : DbContext
{
public virtual IDbSet<State> States { get; set; }
}
public class SampleDatastoreInitializer : DropCreateDatabaseAlways<StateContext>
{
protected override void Seed (StateContext context)
{
var states = new List<State>
{
new State { Abbr = "NY", Name = "New York" },
new State { Abbr = "CA", Name = "California" },
new State { Abbr = "AL", Name = "Alabama" },
new State { Abbr = "Tx", Name = "Texas" },
};
states.ForEach(s => context.States.Add(s));
context.SaveChanges();
}
}
This will actually embed the data in a cache, the DropCreateDatabaseAlways means that it will drop the cache and recreate it no matter what. If you use some other means of IDatabaseInitializer, and your model has a unique key, you might get an exception error, where you run it the first time, it works, but run it again and again, it will fail because you're violating the constraints of primary key (since you're adding duplicate rows).
Problem I had with this:
This seems like it should only be used to provide sample data when you're testing the application, not for production level. Plus I'd have to continously create a new initializer for each context, which plays a similar problem noted in solution 1 of maintainability. There is nothing automatic happening here. But if you want a way to inject sample code without hooking up to a database, this is a great solution.
Solution 3: Entity framework with Repository (In-memory persistence)
I got this solution from this website:
http://www.roelvanlisdonk.nl/?p=2827
He first sets up an edmx file, using EF5 and the code generator templates for EF5 dbcontexts you can get from VS extension libraries.
He first uses the edmx to create the contexts and changes the tt templates to bind to the repository class he made, so that the repository will keep track of the datacontext, and provide the options of querying and accessing the data through the repository; in his website though he calls the repository as MemoryPersistenceDbSet.
The templates he modified will be used to create datacontexts that will bind to an interface (IEntity) shared by all. Doing it this way is nice because you are establishing a Dependency Injection, so that you can add any entity you want through the T4 templates, and there'd be no complaints.
Advantage of this solution:
Wrapping up the edmx in repository pattern allows you to leverage the n-tier architecture, so that any changes done to the backend won't affect the front end, and allows you to separate the interface between the front end and backend so there are no coupled dependencies. So maybe later on, I can replace my edmx with petapoco, or massive, or some other ORM, or switch from in-memory persistence to fetching data from a database.
I followed everything exactly as explained. I made one modification though:
In the t4 template for .Context.tt, where DbSetInConstructor is added, I had the code written like this:
public string DbSetInConstructor(EntitySet entitySet)
{
return string.Format(
CultureInfo.InvariantCulture,
“this.{1} = new BaseRepository();”,
_typeMapper.GetTypeName(entitySet.ElementType), entitySet);
}
Because in my case I had the entityset = Persons and entityname = Person. So there’d be discrepancy. But this should cover all bases.
Final step:
So whether you picked solution 1, 2, or 3. You have a method to automatically populate your application. In these cases, the stubs are embedded in the code. In my case, what I've done is have my web server (containing my front end app), contact my data server, have the data server query the database. The data server will receive a dataset, serialize it, and pass it back to the web server. The web server will take that dataset, deserialize it, and auto-map to an object collection (list, or enumberable, or objectcollection, etc).
I would post the solutions more fully but there's way too much detail between all 3 of these solutions. Hopefully these solutions would point anyone in the right direction.
Dependency Injection
If anyone wants some information about how to allow DI to api controllers, Peter Provost provides a very useful blog that explains how to do it. He does a very very good job.
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
few more helpful links of repository wrapping up edmx:
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx
http://www.codeproject.com/Articles/688929/Repository-Pattern-and-Unit-of
this is really annoying
I have something like this:
class Person {
..properties id, name etc..
}
class Task {
..properties id, name etc..
Person Moderator {get;set}
}
public class DataModel : DbContext {
public DbSet<Task> Tasks { get; set; }
public DbSet<Person> People { get; set; }
}
I can then create new tasks and add People objects to the task and save, and I can see the data correctly saved in the sql backend - each Task saved has the correct Person id saved
with it and the Person with that id is saved back as well.
But when I try and get back a task, the person object is always null.
using (DataModel db = new DataModel()) {
Task t = db.Tasks.SingleOrDefault(p => p.Id == 22);
assert(t.Name.Lenght>0)
assert(t.Moderator != null) // always null!!!!!!
....
}
What do I have to do to get the whole object graph bought back? Do I have to do a join in the SingleorDefault call? seems a bit wrong somehow.
Did I mention this is really annoying.
TIA,
Two options for you. By default the code first / dbContext model returns a proxy object that derives from your model (this is important to understand when you run into JSON serialization issues). The proxy object uses lazy loading of associations but only under certain circumstances. The Moderator property has to be declared as virtual so that the proxy can override it and do the lazy loading for you.
However lazy loading can create a problem called Select N+1. If in most cases you only need the Task and not the Moderator, this won't be a problem. However if you frequently display a list of tasks and their associated moderators, you will effectively have to run an extra round trip to the database for every task in that list in addition to the 1 for the original list(e.g. for a list of 100 tasks you would do 101 queries to display the tasks and their moderators).
To get around this, EF provides the Include operator, this forces the relation to load. Use it as such
Task t = db.Tasks.Include(t=>t.Moderator).SingleOrDefault(p => p.Id ==
22);
Hope this helps.
You have lazy loading turned off for your Moderator property, so it will only be loaded if you explicitly do so using Load().
You can force EF to eagerly load your related Person entity by using the Include() method in your query like this:
Task t = db.Tasks.Include(x => x.Moderator).SingleOrDefault(p => p.Id == 22)
There is a pretty good overview in this article.
I'm using Entity Framework 4 and a Dynamic Data site to expose a bare-bones admin interface to a few users. Working pretty well in general, but I have run into this one problem on a couple of fields on my model.
Several tables have some audit-related fields - CreatedBy, CreatedDate, ModifiedBy, and ModifiedDate. These fields are required in the database and the associated models are marking the properties as non-nullable (all as it should be). However I am handing setting the values for these fields in code - the field templates for the field types mark these specific fields as disabled on the page, and in the SavingChanges event I set these fields to the appropriate values. All works great when I'm updating an existing item.
The problem comes in when I try to create a new item. I want these fields to remain empty on the page and be auto-populated by my code when submitted, but the Field Templates set up RequiredFieldValidators for these fields and won't let me submit them without a value. Normally this would be great, except that I want to prevent EF from validating these fields at the point of page submission.
I realize that I could mark the fields as nullable in the database and that would resolve the issue - it would probably even be just fine from the data standpoint, but I'm not comfortable with doing so - for one thing it's not unlikely that some of the models these fields appear on will be bulk loaded, possibly by someone else, at a later date. I would rather still have the database enforce the non-nullability of these fields. In the field templates I've tried moving the built-in SetUpValidator() call for the RequiredFieldValidator not to run when these specific fields are being loaded, and I've also tried disabling the RequiredFieldValidators and forcing their IsValid property to true. None of these actions allows me to submit the page.
Is there a way to tell EF/Dynamic Data to skip the validation for some fields?
EDIT
As noted below, I also tried marking them nullable in the model and not in the database, which caused an error: Problem in mapping fragments...Non-nullable column...in table...is mapped to a nullable entity property.
EDIT #2
I have found a solution that works, but requires modifying the auto-generated designer file for the entity set, which is fragile at best. I would love to know a "righter" way to do it, but if nothing becomes apparent in the next couple of days I'll post my own answer.
So here are the edits I found I had to make. When allowing the tool to create the entities in the edmx Designer.cs file I get properties like these:
for a datetime on the server side
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime CreatedDate
{
get
{
return _CreatedDate;
}
set
{
OnCreatedDateChanging(value);
ReportPropertyChanging("CreatedDate");
_CreatedDate = StructuralObject.SetValidValue(value);
ReportPropertyChanged("CreatedDate");
OnCreatedDateChanged();
}
}
for a varchar
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String CreatedBy
{
get
{
return _CreatedBy;
}
set
{
OnCreatedByChanging(value);
ReportPropertyChanging("CreatedBy");
_CreatedBy = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("CreatedBy");
OnCreatedByChanged();
}
}
To make it work without validation for a DateTime property setting the IsNullable parameter of the EdmScalarPropertyAttribute to true is sufficient to avoid the issue. For the String property you also have to change the 2nd parameter of the SetValidValue method call to "true."
All of this said, the only reason that I'm leaving this as it is is because I don't expect to have to regenerated the entities more than once or twice before we move to a different platform for this site. And in this case, merging the version in I have checked in to git with the version generated by the tool allows me to avoid most of the headaches,
Here is my meta information for a read-only auto generated date field. I don't get validation controls validating these fields. Hope this helps.
[ReadOnly(true)]
[DataType(DataType.Date)]
[Column(IsDbGenerated = true, UpdateCheck = UpdateCheck.Never, AutoSync = AutoSync.Never)]
[UIHint("DateTime")]
[Display(Name = "Modified", Order = 1000)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
public object DateModified { get; private set; }