Document design with multiple embedded documents - mongodb

I have a Schema question regarding MongoDB. I have a User table with 6 different related entities.
public class Profile
{
public List<Entity1> {get;set;}
public List<Entity2> {get;set;}
public List<Entity3> {get;set;}
public List<Entity4> {get;set;}
public List<Entity5> {get;set;}
public List<Entity6> {get;set;}
}
When i show the profile page, i have to show all the data related to the profile. After reading MongoDB tutorials, my initial design was to embedd all the six documents inside Profile document. But i am concerned that, it may exceed the document size. So currently i have 6 seperate collections, and each collection entity has a ProfileId(Indexed) in it. On Profile view, i make 6 different database calls based on ProfileId and show all the results.
public class Entity1
{
public int ProfileId {get;set;}
......
........
}
Is this acceptable ?
Thanks !

As of mongo 2.4, the maximum document size is 16MB which is quite a lot without any BLOBs or something. So if you always want to retrieve the entire profile embedding all the lists is definitely your first choice.
Without knowing your use case, I typically experience apps built on top of mongo becoming slow due to too many queries, in particular if you're working with a remote database. Remember that mongo does not support joins, so accessing 7 collections really means 7 round-trips!
Hence, I would start with the embedded solution and do a bit of document size measuring from time to time in order to check the size. If 16MB is really not enough, you will probably have a single entity list growing too large - in that case, I would only extract this single list to its own collection.
If you want to have maximum flexibility like being able to switch easily while you are evaluating your document sizes, you could additionally store your data to the 6 other entity collections as you are doing now, but without ever reading them. If you have to switch later on, you simply change the corresponding queries and delete the embedded fields from the Profile collection.

Related

How do I load an aggregate object from db in AxonFramework or any other Event-Sourcing frameworks?

I've had the question for a long time. For most samples on Internet. They always creat one aggregate object first and then operate the aggregate objects. My question is, how can I load one from db other than create one every time. I'll take e-sopping as an example. I treat one product as an aggregate object. I can't load all of them into my program memory. So how can I do?
What I do is, I write another constructor whit the parameter UpdateProductCommand as well as the constructor with parameter CreateProductCommand. In this constructor, I load it from db.Is this OK?
class Product{
public Product(){}
#CommandHandler
public Product(CreateProductCommand command){
apply(new CreateProductEvent(command.id));
}
#CommandHandler
public Product(UpdateProductCommand command){
load(command.id)
...
apply(new UpdateProductEvent(command.id));
}
}
I am assuming that you want to use State-Stored Aggregates and you can check the link for more info.
To give you some light, I would have to see which field have you marked with #Id and #AggregateIdentifier but assuming you have one String id (which is your command.id and the #TargetAggregateIdentifier as well), Axon is responsible for loading the Aggregate from the database based on that field. Having said that, you don't have to take care of it yourself, just focusing on your business logic (which means validations) and applying new values when needed.

Building models in NOSQL

We are trying NOSQL Document database (ravenDB) and we are asking ourselves some questions.
This is our models :
public class User
{
public Guid Id {get;set}
public string Name {get;set;}
}
public class Video
{
public Guid Id {get;set;}
public string Nom {get;set;}
public DateTime PublishDate {get;set;}
public User Publisher {get;set;}
public Uri Adress {get;set;}
}
By default, a video can not be read by anyone.
You can add the rights to see the video at a user or a group of user.
You can recommand a video to a user or a group of user(the rights to see the video is added automatically).
What is the best way to design the models for a NOSQL Document database considering the following use case :
A user is publishing a video he can choose which group(s)/user(s) can see the video and recommend the video to some user(s)/group(s)
A user withdraw the rights to see the video at some user(s)/group(s)
Get the last N videos that a user has been authorized to read
Get the last N videos that have been recommended for a user
We are considering the following :
Add 2 List for each model (VideosReadable, VideosRecommended and UsersAllowedToRead, UserRecommended) where the first list contains all the elements of the second
Add a list of Tuple for each model (ListTuple<User, bool>> and List<Tuple<Video, bool>>), the bool indicates that if it is recommended.
Add a Document UserVideoLink
Which one would be the easiest model for querying ? Is there other better alternatives?
It all comes down to quantities. How many potential users total? How many potential videos total? How many recommendations and assignments? How often will the data change? There is no one best answer.
You may find, for example, that if you have a lot of everything that you are better off creating separate documents to model the active bits, such as a separate class and document to model a Recommendation and another to model an Assignment.
Then again, if one user only has access to a handful of videos, you may find it easier to embed a list of VideoIDs in each user, or a list of Video objects which may or may not be the full video document or just a be a small denormalized piece of data.
You'll have to experiment and decide what works best for you.
However, I'd stay away from using Tuple. They get a bit messy. You'd do better with a class of your own creation for that purpose.
I would also avoid a name like UserVideoLink - that doesn't fit the DDD ideas very well. Think of it more as what you are modeling instead, such as a Recommendation.
Some of this may sound like very relational-database thinking, but it does have a place in document databases also. Just because a document can have structure doesn't mean that everything has to go in a single document. Try to model your domain first using DDD concepts. Then everything you've identified as an "Aggregate Root" entity, and all child entities thereof, (usually) belong in a single document.

Does ASP .Net MVC have anything similar to Java's [Transient] attribute?

As the title says, is there a way in ASP .Net MVC (4) to mark a models property as "Transient" i.e. not persist to database.
I am looking to make a model to which most of the data is stored in an external system, I simply need to store a reference of that record in my system and fetch the data from the external system when needed. Am I able to do this using attributes or do I need to implement some sort of View Model?
As it is part of the name of the language, I think that the best practice for you would be to include it in a ViewModel, populate it when you grab the data at first in your controller, and just not do anything with it when you go back to the controller to save it.
The only thing that comes close to what you're describing is the NotMapped attribute for Entity Framework which will know not to create a column for that field or persist anything to the database for it. But those are typically only used for properties that are precalculated (i.e. you want a quick way to ask for the sum total of 3 of your fields).
for others who have the same problem, you can use internal keyword which will prevent data from converting to json:
internal string Attr { get; set; }
You can use as below for transient attribute filed in .net core.
[NotMapped]
public String ErrorMessage { get; set; } = "";

EF with Azure - Mixing SQL Server and Windows Azure Storage

I want to use two different data sources in my Azure project:
a SQL Server that contains basic partial info regarding an item (allows indexable data and spatial search)
a Windows Azure Storage that contains full remaining info regarding an item (retrieved by key)
In this way I can combine the powerful of SQL Server with the easy scalability of Windows Azure Storage.
Imagine this Domain POCO class:
class Person
{
string Id { get; set; }
string Name { get; set; }
byte[] Picture { get; set; }
string Biography { get; set; }
}
I would like to use Entity Framework with fluent mapping to let EF understand that the properties Picture and Biography must be loaded from Windows Azure Storage (table, blob) instead of SQL Server (possibly Lazy loaded).
There's a way with EF (or NHibernate) to do this or I have to implement my own ORM strategy?
Thanks
I don't think you can let EF know about Azure storage but you can map only necessary properties to a specific table. For example,
modelBuilder.Entity<Person>().Ignore(p => p.Picture);
So assuming that you have a repository class for your Person class, what you want can be easily achieved by filling the repository class with Azure storage API and EF.
You're trying to solve this problem too early (at the DAL) in my opinion. Look at the web, it fetches large data (e.g. pictures) in a separate call to the server. That has scaled very well. The picture data is not included in the document itself for a reason, it would just slow everything down and it would not be very fault tolerant. If you put them together in one entity you've got the fast entity retrieval that is slowed down by your picture server as they both have to come together before leaving towards your business layer and finally towards the presentation layer. And in the business layer this data is probably just wasting memory (that's why you want to lazy load it). So I think you're making the decision too early. What you describe as your domain object looks like a domain object of the presentation layer to me, similar to a ViewModel. I'm not too big into domain driven design, but while there is a general model of your application, I assume that each part of your application will require a slightly different implementation of that model.
Regarding lazy loading, if you have that enabled and you attempt to send your object over the wire, even if Picture was not loaded, it will get serialized since the data contract serializer (or any other) will call get on your property.
That's probably not the answer you wanted, but I felt that I had to say this. Of course I am open to comments and criticism.

How to do role-based access control for a franchise business?

I'm building the 2nd iteration of a web-based CRM+CMS for a franchise service business in ASP.NET MVC 2. I need to control access to each franchise's services based on the roles a user is assigned for that franchise.
4 examples:
Receptionist should be able to book service jobs in for her "Atlantic Seaboard" franchise, but not do any reporting.
Technician should be able to alter service jobs, but not modify invoices.
Managers should be able to apply discount to invoices for jobs within their stores.
Owner should be able to pull reports for any franchises he owns.
Where should franchise-level access control fit in between the Data - Services - Web layer?
If it belongs in my Controllers, how should I best implement it?
Partial Schema
Roles class
int ID { get; set; } // primary key for Role
string Name { get; set; }
Partial Franchises class
short ID { get; set; } // primary key for Franchise
string Slug { get; set; } // unique key for URL access, eg /{franchise}/{job}
string Name { get; set; }
UserRoles mapping
short FranchiseID; // related to franchises table
Guid UserID; // related to Users table
int RoleID; // related to Roles table
DateTime ValidFrom;
DateTime ValidUntil;
Controller Implementation
Access Control with [Authorize] attribute
If there was just one franchise involved, I could simply limit access to a controller action like so:
[Authorize(Roles="Receptionist, Technician, Manager, Owner")]
public ActionResult CreateJob(Job job)
{
...
}
And since franchises don't just pop up over night, perhaps this is a strong case to use the new Areas feature in ASP.NET MVC 2? Or would this lead to duplicate Views?
Controllers, URL Routing & Areas
Assuming Areas aren't used, what would be the best way to determine which franchise's data is being accessed? I thought of this:
{franchise}/{controller}/{action}/{id}
or is it better to determine a job's franchise in a Details(...) action and limit a user's action with [Authorize]:
{job}/{id}/{action}/{subaction}
{invoice}/{id}/{action}/{subaction}
which makes more sense if any user could potentially have access to more than one franchise without cluttering the URL with a {franchise} parameter.
Any input is appreciated.
Edit:
Background
I built the previous CRM in classic ASP and it runs the business well, but it's time for an upgrade to speed up workflow and leave less room for error. For the sake of proper testing and better separation between data and presentation, I decided to implement the repository pattern as seen in Rob Conery's MVC Storefront series.
How to arrange services and repositories?
It makes sense to have a JobService that retrieves any service jobs based on available filters, eg. IQueryable<Job> GetJobs();. But since a job can only belong to one franchise, a function like IQueryable<Job> GetJobs(int franchiseID); could belong in either FranchiseService or in JobService. Should FranchiseService act as a CatalogService (like in MVC Storefront)?
Let me take a stab at answering this. I am in the process of playing with a sample app that touches some of the aspects mentioned. This is not an authoritative answer, merely experience.
Where should franchise-level access control fit in between the Data - Services - Web layer?
This access restrictions should
permeated through your application at
two levels 1) the database 2) the
application layer. In an MVC context I
would suggest having creating a custom
Authorization attribute - this handles
the security between the Web-Services
layer. I would have this attribute do
two things
Get the current roles allowed for the user (either from the DB of it may
be stored in the user session)
Do the checking to see if the user is part of the allowed list of roles.
With regards to the database, this
depends on how you are storing the
data, one database for all franchises
or database per franchise. In the
first case there are several ways to limit
and setup access restrictions for
data to a particular
franchise.
Since franchises don't just pop up over night, perhaps this is a strong case to use the new Areas feature in ASP.NET MVC 2? Or would this lead to duplicate Views?
I think that Areas should be used to
split and group functionality. If you
were to use Areas to split franchises,
this is where I see a duplication of
views, controllers etc. occurring. Duplicate
views can be overcome by using a
custom view engine to specifically
overriding the way MVC locates your
views. Plug: See my answer to ASP.NET MVC: customized design per domain
Assuming Areas aren't used, what would be the best way to determine which franchise's data is being accessed?
As mentioned above, you could the
users session to store basic
information such as the franchise the
user belongs to and the roles etc
assigned. I think the rule I read
somewhere goes along the lines of
"Secure your actions, not your
controllers"
Create you routes etc for the norm and
not for the exception. eg. Is there
currently a business case that says a
user can have access to more than one
franchise?
How to arrange services and repositories?
Have a set of base services or base
classes that will contain all the
information required for a particular
franchise such as the franchiseId.
Th main issue that it does resolve is
that your service methods are cleaner
not having the franchiseId argument.
The repository however may need this
value since as some point you need to
disambiguate the data you are
requesting or storing (assuming one db
for all franchises). However, you
could overcome some of this using IoC.
The downside I see is that
they there will always be calls to the
database every time your objects are
creating (i.e. if the franchise
route were to be used, you would need
to go the database to obtain the
corresponding franchiseId every time
you create a service object. ( I might
be mistaken on this one, since the IoC
containers do have some LifeStyle
options that may be able to assist and
prevent this) You could have
a list of Franchises that are created
on you Application start that you
could use to map your route values to
obtain the correct information. This
part of the answer is scattered, but
the main thing is that IoC will help
you decouple a lot of dependencies.
Hope this helps..