Two part question:
Number 1: What is the best approach in creating a model for an object that references another object, when some of the properties/attributes of the referenced object are not always necessary?
Imagine if you have two objects: PERSON and BUSINESS
Person
+ PersonID
+ Name
+ Age
+ Sex
+ Skill
+ Business *
Business
+ BusinessID
+ Name
+ Address
+ CorporateVision (this is large)
In the example above: A PERSON has a reference to a BUSINESS as their current employer.
In the database, I would have two tables for each object. While in code, using the MVC architecture pattern, I would have two classes for each object. The database would have a foreign-key relationship between BUSINESS-->PERSON, while in code the PERSON object would have a member variable that holds a reference to a BUSINESS object.
Now let's say I want to enumerate on a collection of PERSONS and find out the total number of those that work for a specific company (based on BUSINESS . Name).
Without using MVC, I could just create a function that would query the database and get a count. Simple and efficent.
WITH MVC, I need to instantiate every PERSON object, which in turns, instantiates a BUSINESS object for the reference (if one was not already done for it... the BusinessFactory would check a collection first). Furthermore, it MUST pull in BUSINESS . CorporateVision from the database for every object. And because most of these businesses are Media Marketing Companies, most of their corporate visions are large text blobs. So it is very unnecessary to read CorporateVision from the database when all we need is the name of the business.
I could solve this problem by having changing the PERSON object in code to:
Person
+ PersonID
+ Name
+ Age
+ Sex
+ Skill
+ BusinessID
+ BusinessName
So now when I create my PERSON object, I do a JOIN with BUSINESS and cache the name. Now I can get the BusinessName quickly and efficiently... and I still can get the full BUSINESS object as needed by doing a lookup on the ID. But I just denormalized the model... and I just introduced a new problem... and a new question.
Number 2: How does MVC handle concurrency with a multi-user database?
Lets say while my client application is enumerating (using the enumeration that I mentioned above that finds all people that work for a particular business), another user merged two of the BUSINESS objects.
Now my in-memory collection is wrong because all of the BusinessName caching is stale. The same could be true if I had just left the PERSON . Business as a BUSINESS object reference: The BUSINESS object would be stale.
In summary: I feel that with MVC I lose data retrieval efficiency as well as the loss of the ACIDness of my application. Or am I using MVC wrong?
You seem to mix UI and Data access, while you should minimize their dependencies over another. MVC is actually a pretty broad pattern which describes how application interacts with user. Both your questions are related to data access.
1) MVC is the way you organize UI. So, model is a piece of information you want to make user interact with. Note, business objects are not priority here. If there is a case when use loads a Person class along with several properties from Business, so be it: your second Person rendition is a perfect model for this case. And so on - each use case requires a different model and you should create different model for different scenarios.
If you think it's easier for you to call a function to calculate the number - fine. Remember, you are not bound to business objects here.
With more 'object'-oriented approach we usually solve this reference problem in two ways:
first is lazy loading, with is out-of-the-box feature for modern O/RMs. So you load a person and after a first call to Person.Business, latter is loaded automatically.
second is that you create a special kind UI, which is aware of your data access specifics and either has only fields you use, or requests additional data in an async manner from a client.
2) Again, MVC doesn't handles concurrency, and it shouldn't handle it and shouldn't even bother. It's a concern of data access layer. And there are also several ways to deal with concurrency, major of them are optimistic and pessimistic locks. (With the first one you allow different users to make conflicting changes and try to resolve conflicts when they occur. The second way prevents conflicts by locking updates completely). Again, O/RMs deal with it usually; or you can use your own implementation, but it should be still data access, not MVC part.
Related
There are a lot of questions on syncing state between devices or from external storage to/from the UI. This question is about state within the UI.
The UI may have multiple state objects that can point to one entity.
Eg. Multiple User Models that have the same ID and are essentially the same User in the Database.
The second option is to have a pattern that prevents multiple entities and enforces a single Entity is never duplicated.
Eg. Retrieving a User Model with ID=1 will always return the same Model.
So the options I currently face:
Have multiple Models point to the same DB entity
Enforce a single Instance of a Model reflects a DB entity
Both of these have their tradeoffs:
Have multiple Models point to the same DB entity
This requires syncing the Models with the same ID when a copy if updated.
This becomes non-trivial in implementation.
The current implementation we have is an EntityManager that keeps copies of each model and will propagate writes to all copies.
It however has complexities in syncing due to async writes to the remote copies, reads from other devices and remote fetches as well as reactions (mobx) within models need to ensure they are reacting to a consistent state of the model.
Enforce a single Instance of a Model reflects a DB entity
This requires no work to sync. However we have the complexity of ensuring we don't have any copies of a Model pointing to the same DB entity.
This becomes subject to coding conventions.
Eg.
model.fromJSON({ title: 'foo' })
model.fetch()
Becomes
model = model.fromJSON({ title: 'foo' })
model = model.fetch()
This is hard to understand for new developers and can be missed over time creating hard to debug errors.
The question is how do you generally solve this scenario with a consistent and the least complex in terms of bugs case.
Im at the beginning of my first "real" software project, and I'd like to start off right. The concept of DDD seems like a very clean approach which separates the various software parts, however im having trouble implementing this in reality.
My Software is measurement tracker and essentially stores list of measurement data, consisting of a timestamp and the data value.
My Domain Models
class MeasurementDM{
string Name{get;set;}
List<MeasurementPointDM> MeasurementPoints{get;set;}
}
class MeasurementPointDM{
DateTime Time{get;set;}
double Value{get;set;}
}
My Persistence Models:
class MeasurementPM{
string Id{get;set;} //Primary key
string Name{get;set;} //Data from DomainModel to store
}
class MeasurementPointPM{
string Id{get;set;} //Primary Key
string MeasurementId{get;set;} //Key of Parent measurement
}
I now have the following issues:
1) Because I want to keep my Domain Models pure, I don't want or need the Database Keys inside those classes. This is no problem when building my Domain models from the Database, but I don't understand how to store them, as the Domain Model no longer knows the Database Id. Should I be including this in the Domain model anyway? Should I create a Dictionary mapping Domain objects to Database ids when i retreive them from the Database?
2)The measurement points essentially have the same Id problem as the measurements themselves. Additionally I'm not sure what the right way is to store the MeasurementPoints themselves. Above, each MeasurementPointPM knows to which MeasurementPM it belongs. When I query, I simply select MeasurementPoints based on their Measurement key. Is this a valid way to store such data? It seems like this will explode as more and more measurements are added. Would I be better off serializing my list of MeasurementPoints to a string, and storing the whole list as an nvarchar? This would make adding and removing datapoints more difficult, as Id always need to deserialize, reserialize the whole list
I'm having difficulty finding a good example of DDD that handles these problems, and hopefully someone out there can help me out.
My Software is measurement tracker and essentially stores list of measurement data, consisting of a timestamp and the data value.
You may want to have a careful think about whether you are describing a service or a database. If your primary use case is storing information that comes from somewhere else, then introducing a domain model into the mix may not make your life any better.
Domain models test to be interesting when new information interacts with old information. So if all you have are data structures, it's going to be hard to discover a good model (because the critical element -- how the model entities change over time -- is missing).
That said....
I don't understand how to store them, as the Domain Model no longer knows the Database Id.
This isn't your fault. The literature sucks.
The most common answer is that _people are allowing their models to be polluted with O/RM concerns. For instance, if you look at the Cargo entity from the Citerus sample application, you'll find these lines hidden at the bottom:
Cargo() {
// Needed by Hibernate
}
// Auto-generated surrogate key
private Long id;
This is an indirect consequence of the fact that the "repository" pattern provides the illusion of an in-memory collection of objects that maintain their own state, when the reality under the covers is that you are copying values between memory and durable storage.
Which is to say, if you want a clean domain model, then you are going to need a separate in memory representation for your stored data, and functions to translate back and forth between the two.
Put another way, what you are running into is a violation of the Single Responsibility Principle -- if you are using the same types to model your domain that you use to manage your persistence, the result is going to be a mix of the two concerns.
So essentially you would say that some minimal pollution of the domain model, for example an Id, is standard practice.
Less strong; I would say that it is a common practice. Fundamentally, a lot of people, particularly in the early stages of a project, don't value having a boundary between their domain model and their persistence plumbing.
Could it make sense to have every Domain Model inherit from a base class or implement an interface that forces the creation of Unique Id?
It could. There are a lot of examples on the web where domain entities extend some generic Entity or Aggregate pattern.
The really interesting questions are
What are the immediate costs and benefits of doing that?
What are the deferred costs and benefits of doing that?
In particular, does that make things easier or harder to change?
Background
I'm creating a layered .net core application to handle tracking campaigns for a board game. Because of this there is a lot of data that comes from the game itself, for example:
Characters
Weapons
Equipment
Missions
Objectives that belong to a mission
Rewards that belong to objectives
Etc
The application is not to manipulate this data. This data is typically printed on cards that come with the board game so it won't change. The only changes it may have are when I manually add new characters or something due to a new expansion being released.
As far as the app is concerned, these are similar to how you might have a lookup table of States in the US. The app needs to list them so you can select them, entities in the domain hold references to them, but their actual data is irrelevant to the application itself. It's just lookup data.
Except there is a lot of this data and some of it is related. For example an objective belongs to a specific mission and a reward belongs to a specific objective.
The Problem
If my application was being designed to manage this data there would be no problem. However this is not the case. It is designed to manage "Campaigns", which are 2-5 players sitting down to play a game with these cards. It is managing "instances" of this data that have additional properties.
For example a new campaign is created and a row is added to the Campaign table. Now a mission must be added to it.
I can't just add a reference to the Mission data because I also need to store the outcome of the mission specific to this campaign. So I create a CampaignMission entity that references the mission data, the campaign id, and has a column for the mission outcome.
But that Mission data had related Objective data. The data just holds things like objective name, description, rewards etc, but in the campaign I also need to store the outcome of this objective specific to this CampaignMission. So again I create a CampaignObjective that references the Objective data, the CampaignMission, and has a column for the objective outcome.
Before you know it I am doing this for everything. CampaignCharacter, CampaignWeapon, CampaignReward. I feel like I'm just replicating the structure of the game data, relationships included.
Where the game data has relationships, my Campaign entities feel like they're mirroring the relationships to the point where, from the same object, you can access the same piece of game data by following two separate paths, the original game data relationship or the Campaign entity "replica" relationship.
For example if I want the name of the first reward for the first objective in the first campaign mission, you can access it in two ways:
Campaign.CampaignMissions[0].Mission.Objectives[0].Rewards[0].Name
Campaign.CampaignMissions[0].CampaignObjectives[0].CampaignRewards[0].Reward.Name
Both of these point to the same piece of game data. I really feel like there should only be one path:
Campaign.Missions[0].Objectives[0].Rewards[0].Name
Where I'm Stuck
I'm not sure if this is normal but it all just feels wrong. Almost as though the game data shouldn't even be part of the application. I mean the game data could be hosted on some 3rd party API and it wouldn't make any difference to my actual application. It's just data I need to read but I feel it's impacting my app structure in ways it shouldn't be.
My application doesn't really need to know the difference between Mission game data and a Mission in a campaign. All it needs to care about is that a campaign can have missions, and those missions have a name etc and an outcome. It doesn't feel like the Mission game data itself needs to be an entity in my domain.
What I've Tried
I tried keeping single entities in my domain and keeping them separate in my database. So for example a Mission in the domain would include both the game data fields like mission name, the mission outcome and a list of domain Objectives.
When a domain Mission for a campaign is requested from the data layer, the entry is retrieved from the CampaignMission table, along with its game data from the Mission table, then flattened via AutoMapper and returned to the domain as a single Mission entity containing everything.
This just caused a bit of a nightmare with Entity Framework and handling the mappings back and forth between data layer and domain because the CampaignMission in the database also had CampaignObjectives which linked to Objectives that also had to be flattened etc, and I had to keep track of the primary keys for all of these throughout my domain so everything could be unflattened and mapped back again when I want to persist something. It just didn't make sense, in terms of tracking primary keys/identity, for a single domain entity to be represented by entries in multiple tables.
What I'm Now Considering
I'm considering just moving all of the game data into a totally separate project, completely unrelated to my application. My application could then query project as though it was some third party API or something and get any data it needs and I can keep it all out of my solution.
Since the game data would no longer have IDs in my application, when I add a mission to a campaign it would simply have a column for "name" which would hold the mission name. When I want to use that mission I would grab it from the db and map it to a domain entity, so at this point it contains the campaign-specific data such as mission outcome, and also the name. Then I'd query the game data project using the mission name and map all the returned data back on to the entity as well, leaving me with a complete entity.
This is essentially replicating the behaviour of what I already tried but removing the need to track identity for the game data by simply using a name that I can query. It removes the concept of backing game data from my domain and leaves me with a single entity, Mission.
The Question
I've wasted a lot of time on this so far and I'm sure it must be a common problem in similar types of applications. I was wondering if anyone had a better solution for dealing with this kind of situation before I go ahead and try completely separating the data.
I have to admit, typing out the "What I'm Now Considering" section has clarified a few things for myself but I would still love to hear if there is a better way.
Thank you in advance if anyone reads all of this.
Here's what you should be doing. First, add the game data entities to the DbContext as DbQuery<T>:
public DbQuery<Campaign> Campaigns { get; set; }
This will allow you to query it, but will not allow changes. Then, since the game data is static, you might want to actually just persist it on a singleton, which you can then inject where you need it.
In either case, on the actual campaign data that's being persisted, you should only store the id of the game data concept. For example, MissionId, not CampaginMission.Mission. When you need the actual Mission info, just look it up based on the MissionId, either directly from your DbQuery<Mission> property on your context or your singleton class.
I haven't been able to find an answer to my question so far, and I suppose I have to ask my first question some time. Here goes.
I have a Data Access Layer that's responsible for interacting with various data storage elements and returns POCOs or collections of POCOs when querying out things.
I have a Business Layer that sits on top of this and is responsible for implementing business rules on objects returned from the Data Access Layer.
For instance, I have a SQL Table of Dogs, my data access layer can return that list of dogs as a collection of Dog object. My business layer then would do things like filter out dogs below a certain age, or any other filtering or transformation that had to happen based on business rules.
My question is this. What's the best way to handle filtering objects based on related records? Let's say I want all the people who have Cats. Right now my data access layer can return all the cats, and all the people, but doesn't do any filtering for me.
I can implement the filtering via a different data access method (i.e. DAO.GetCatPeople()) but this could get complicated if I have a multitude of related properties or relationships to handle
I can return all from both sides and do the matching myself all in the business layer, which seems like a lot of extra work and not fully utilizing the sql server.
I can write a data filtration interface and if my data access layer changes this layer would have to change as well.
Is there some known best practices here I could be benefiting from?
The view I take is that there's two "reasons" why you'd access data: Data centric and Use Case centric.
Data Centric is stuff like CRUD and other common / obvious stuff that is a no brainer.
"Use Case" centric is where you define an interface and matching POCO's for a specific purpose. [It's possible I'm missing some common terminology here, but Use Case centric is what I mean]
I think both types are valid. For the use case driven ones it's going to be mostly driven by business focused use cases, but I can see edge cases where they could be more technically driven - I'd say that was ok as long as they didn't violate any business rules or pervert your domain model.
Should Cats and Dogs know about each other? If they exist within the same domain model, and have established relationships within that model - then yes of course you should be able to make queries like GetCatPeople().
As far as managing the complexity goes, rather than GetCatPeople() you could have a more generic method that took an attribute as a parameter: GetPeopleByAnimal(animal).
I'm working on a 2-tier application where WinForms client makes direct calls to the database. In one of the scenarios I need to display a list of Customer entities to a user. The problem is that Customer entity contains a lot of properties (some quite heavy) and I need only two of them - first and last names. So to improve performance and make presentation logic clearer I want to create some kind of a CustomerSummaryViewModel class with required properties only and use NHibernate's projections feature to load it. My concern here is that in this case my data access logic becomes coupled with presentation and to me it seems conceptually wrong.
Do you think this is ok or there are better solutions?
I think you can consider the CustomerSummaryViewModel as report (CustomerSummaryReport). It is fine to query your entities for scenario's like this and treat them as reports. Most reports are more complex, using multiple entities and aggregate queries. This report is very simple, but you can still use it like a report.
You also mention that the performance is significant. That is another reason to use a separate reporting query and DTO. The customer entity sounds like one of the "main" entities you use. That it takes a significant amount of time to retrieve them from the database with lazy-loaded properties not initialized, can be a warning to optimize the customer entity itself, instead using reporting queries to retrieve information about them. Just a warning because I have seen cases where this was needed.
By the way, you can consider linq instead of projections for the easier syntax like:
var reports = session.Linq<Customer>()
.Where(condition)
.Select(customer => new Report
{
FirstName = customer.FirstName,
LastName = customer.LastName
})
.ToList();