RavenDB Persisting chain of relationships - ravendb

I'm working on a collaborative document editing tool that's going to use RavenDB for persistence. In my domain I have a document class that looks like this.
public class Document
{
public string Id { get; private set; }
public string Name { get; set; }
public IRevision CurrentRevision {get; private set; }
public string Contents {get { return CurrentRevision.GenerateEditedContent(); }}
}
As you can see that document then has a CurrentRevision property that points to an IRevision object that looks like this.
public interface IRevision
{
IRevision PreviousRevisionAppliedTo { get; }
IRevision NextRevisionApplied { get; set; }
Guid Id { get; }
string GenerateEditedContent();
}
So the basic idea is that the document's contents are generated on the fly by checking out the current revision, which in turn checks it's parent revision, and so on and so forth.
Out of the box, RavenDB doesn't seem to handle persisting this chain of object references the way I need it to. I've been trying to persist it by just calling Session.Store(document), and hoping that the list of associated revisions would get stored as well. I've looked into some pieces of the RavenDB framework like custom serializers, but I can't figure out a clear path that would allow me to deserialize and reserialize the data as I would like. What's a good way to handle this situation.

Related

Confused about DTOs when reading and editing. How to desing DTO for filling the form in VUEjs app?

I am trying to develop an enterprise-level application. I have domain and application services. I have created my DTOs for multiple purposes separately. But confused about which way I should use them from the API viewpoint.
I have complex objects lets say,
public class Entity{
public int Id { get; set; }
public string Name { get; set; }
public int? ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public class Manufacturer{
public int Id { get; set; }
public string Text { get; set; }
}
And I have corresponding DTOs designed with composition now. It was separated before.
public class EntityBaseDto{
public string Name { get; set; }
}
public class EntityReadDto : EntityBaseDto{
public string Manufacturer { get; set; }
}
public class EntityWriteDto : EntityBaseDto{
public int? ManufacturerId { get; set; }
}
Now the question is,
I have a table which is filled with List<EntityReadDto> which is clear. Before, EntityReadDto also had the ManufacturerDto as fully included with id and text. Whenever I require to edit one of the entries from the table I was able to load the dropdown selected items or list of tags etc with the ids attached to the Manufacturer objects within ReadDtos. Now it is not possible. Since I wanted to simplify the codes I just converted them to strings that are read-only. Now I have created another endpoint to get an editable version of the record when needed. Ex: EntityWriteDto will be used to fill the form when the edit is clicked on a specific item. The manipulation will be carried on that DTO and sent with the PUT type request to edit the record.
I am not sure if this approach is ok for these cases. What is the best practice for this? I have many objects related to the entities from other tables. Is it ok to make a call to get an editable version from the backend or need to have it right away in a VUEjs app?

Reference another class using an index vs storing entire instance

In a class which needs to "contain information" about another class (sorry I don't know the terms for this), should I store the reference to that other class as something like an integer/id, or should I store it as an instance of the other class? What is this called, if there is a name for it?
As a very basic example, an app where we want to store what a user's favorite restaurant is:
public class User {
public int id { get; set; }
public string name { get; set; }
// id of restaurant...
// public int favoriteRestaurantId { get; set; }
// ...or entire instance of Restaurant type
// public Restaurant favoriteRestaurant { get; set; }
}
public class Restaurant {
public int id { get; set; }
public string name { get; set; }
}
Note: if you think this is off topic, please explain why this question would be allowed and is a highly rated/useful question, but mine is not: Interface vs Base class Or at the very least tell me what this is "called" so I can research it more myself. As far as I can tell from Stackoverflow's FAQ this question is on topic.
Your first variant
public int favoriteRestaurantId { get; set; }
only makes sense if you are only interested in the id and not the other attributes (name) of the restaurant object. Otherwise you will need some external container that stores all restaurant objects and have to search the container for the restaurant with the given id.
In your second variant
public Restaurant favoriteRestaurant { get; set; }
if you write
someUser.favouriteRestaurant = someRestaurant;
this also stores a reference to an existing someRestaurant. It will not copy the whole object. at least not in languages like C# and Java.
Only if you do something like
someUser.favouriteRestaurant = new Restaurant(someRestaurant);
the user will have its own copy of the restaurant object.
There are cases where this would make sense but in your example it is probably not a good idea for two reasons:
If for example the name of the someRestaurant changes, this should also change the name of favouriteRestaurant. This will not happen automatically if favouriteRestaurant is a copy.
It is a waste of memory.

Automapper not mapping between two objects (which are virtually the same for all intents and purposes)

Yes, this is ANOTHER "Automapper not mapping" question. Either something broke or I'm going the stupid way about it. I'm building a webapp with ASP.NET Core 2.1 using AutoMapper 3.2.0 (latest stable release at the time) though I have tested with 3.1.0 with no luck either.
Question
Simple object to be mapped to another. For the sake of testing and trials, these are now EXACTLY the same, yet still automapper gives:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
NotificationModel -> NotificationViewModel
ProjectName.Models.Dashboard.NotificationModel -> ProjectName.Models.Dashboard.NotificationViewModel
The strange thing is, I have previously mapped this model set 7 ways to sunday in the Startup.cs file with the only thing changing is my facial expression. Other maps work as indicated using similar, if not the same code for them.
The Models
NotificationModel.cs
public class NotificationModel
{
public int Id { get; set; }
public string Content { get; set; }
public DateTime CreateTS { get; set; }
public bool FlagRead { get; set; }
public bool FlagSticky { get; set; }
public bool FlagReceipt { get; set; }
public string ReceiptContact { get; set; }
public string UserId { get; set; }
public bool CANCELLED { get; set; }
}
NotificationViewModel.cs
public class NotificationViewModel
{
public int Id { get; set; }
//Reminder, this model has been amended to exactly represent that of the original model for testing purposes.
public string Content { get; set; }
public DateTime CreateTS { get; set; }
public bool FlagRead { get; set; }
public bool FlagSticky { get; set; }
public bool FlagReceipt { get; set; }
public string ReceiptContact { get; set; }
public string UserId { get; set; }
public bool CANCELLED { get; set; }
}
Startup & Automapper Config
Mapper.Initialize(cfg =>
{
// Some other mappings removed for clarity.
cfg.CreateMap<GroupViewModel, GroupModel>().ReverseMap();
//cfg.CreateMap<EntityViewModel, EntityModel>().ReverseMap().ForAllOtherMembers(opt => opt.Ignore());
cfg.CreateMap<NotificationModel, NotificationViewModel>().ForAllMembers(opt => opt.Ignore());
cfg.CreateMap(typeof(NotificationViewModel), typeof(NotificationModel));
//I even left out the .ReverseMap, for testing purposes.
});
Mapper.AssertConfigurationIsValid();
Usage
NotificationViewModel test = _mapper.Map<NotificationViewModel>(item); << Which is where I receive the exception.
Other Attempts
Ok, so I've been through some more articles explaining different things and subsequently tried the following respectively:
cfg.CreateMap(typeof(NotificationModel), typeof(NotificationViewModel));
cfg.CreateMap<NotificationModel, NotificationViewModel>().ReverseMap().ForAllMembers(opt => opt.Ignore());
cfg.CreateMap<NotificationModel, NotificationViewModel>().ForAllOtherMembers(opt => opt.Ignore());
Along with:
NotificationViewModel test = _mapper.Map<NotificationViewModel>(item);
_mapper.Map(item, typeof(NotificationViewModel), typeof(NotificationModel));
NotificationViewModel existingDestinationObject = new NotificationViewModel();
_mapper.Map<NotificationModel, NotificationViewModel>(item, existingDestinationObject);
I've tried amending the .Map()/.Map<> usage several ways, none of which seemed to yield anything but an exception about not having been configured.
So short of manually writing a conversion for this object (which is simple enough for its purpose), I am in dire need of a solution here. If not to use, then atleast to learn from and help others facing the same.
UPDATE
IT WORKS!
Scanning through the project, I noticed that somewhere in previous documentation - I read about creating a type of "config" class that just inherits from an abstract class called Profile. In this class you will also be able to define your maps, yet what is strange is that I am not able to drop this class and simply use the config maps setup in my Startup.cs file. Automapper will refuse to hold any maps that are not defined in this separate class. The below seems to get me what I need, however I still need an explanation as to why Automapper doesn't function as desired without it:
public class AMConfig : Profile
{
public AMConfig()
{
CreateMap<ManageUserModel, IndexViewModel>();
CreateMap<IndexViewModel, ManageUserModel>();
CreateMap<NotificationViewModel, NotificationModel>().ReverseMap();
CreateMap<List<NotificationViewModel>, List<NotificationModel>>().ReverseMap();
CreateMap<TaskViewModel, TaskModel>().ReverseMap();
}
}
Thanks!
Scanning through the project, I noticed that somewhere in previous documentation - I read about creating a type of "config" class that just inherits from an abstract class called Profile. In this class you will also be able to define your maps, yet what is strange is that I am not able to drop this class and simply use the config maps setup in my Startup.cs file. Automapper will refuse to hold any maps that are not defined in this separate class. The below seems to get me what I need, however I still need an explanation as to why Automapper doesn't function as desired without it:
public class AMConfig : Profile
{
public AMConfig()
{
CreateMap<ManageUserModel, IndexViewModel>();
CreateMap<IndexViewModel, ManageUserModel>();
CreateMap<NotificationViewModel, NotificationModel>().ReverseMap();
CreateMap<List<NotificationViewModel>, List<NotificationModel>>().ReverseMap();
CreateMap<TaskViewModel, TaskModel>().ReverseMap();
}
}

How to access many to many object in .NET MVC via Razor

Using EF 7 I have an object that references a many to many table, using code first method.
public class EventUser
{
public string UserId { get; set; }
public User User { get; set; }
public int EventId { get; set; }
public Event Event { get; set; }
public string AdditionalInfo { get; set; }
}
I can pull a list of these when knowing EventId and display them in Razor. I want to link to each one of these objects back to the controller so a user could edit the AdditionalInfo field. Since the object doesn't have just one Id field, how can I send the appropriate data to the controller to access this object, since just using one Id will not be enough.
At this point, I can achieve this using:
<a asp-action="EditEventUser" asp-route-EventId="EventUser.EventId" asp-route-UserId="EventUser.UserId">Edit Event User</a>
But, I would like to know if I am ignorant about some other way this can be achieved in a cleaner way (if there is such a way).

Is the properties in Entity must be virtual when using FluentNhibernate?

Which entity FluentNHibernate uses as entity
I create some entity in Domain(or BLL), such as the following:
public class Role
{
public long ID { get; protected set; }
public string Name { get; set; }
public string Description { get; set; }
public List<User> Users { get; set; }
public Role()
{
Users = new List<User>();
}
}
And I want make use of FlunetNHibernate to map them, but get errors:
The following types may not be used as proxies:
Freeflying.Domain.Core.Profile: method get_ID should be 'public/protected virtual' or 'protected internal virtual'
Yes, I recall the programmer requirement when use FluentNHibernate, the entity should be like this:
public class Role
{
public virtual long ID { get; protected set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
But It looks wired. Do you think so? How do you do when using FluentNHibernate? I don't want go back to Domain layer and add virtual for every property.
This is a basic requirement for using NHibernate; It allows NHibernate to generate a proxy class that descends from your class for lazy loading and such.
I have not seen a method of removing this requirement, though if such a thing is possible it would mean that you could not use lazy loading of objects and/or properties.
Here's a blog post that explains this a bit more; It also offers a way to avoid marking your properties as virtual, although I would really recommend that you do not use this method (marking classes to avoid lazy loading) as the benefits of lazy loading in most circumstances far outweigh the cost of making your properties virtual.