Database design for storing user settings - c#

public interface IPlugin
{
void Execute();
}
public class FirstPlugin : IPlugin
{
public string SomeSetting1 { get; set; }
public void Execute() { }
}
public class SecondPlugin : IPlugin
{
public string SomeSettingA { get; set; }
public string SomeSettingB { get; set; }
public string SomeSettingC { get; set; }
public void Execute() { }
}
I have a system that allows usesr to select one or more plugins. In the code above, I have an IPlugin interface that is implemented by many classes. Each class can have their own set of properties and each user can configure those properties.
For example, User A selects only the first plugin and configures SomeSetting1 to have a value of "ABC".
User B selects both plugins, but configures the first plugin's SomeSetting1 to have a value of "XYC".
public class User
{
public User(IPlugin[] plugins)
{
}
}
When I instantiate a user, I want to get a list of plugins that the user has configured and those plugins should be hydrated with what the user has configured.
However, I'm drawing a blank on how to design the database to be able to store information in this format. I could have a table:
User | Plugin
----------------
A | ...
B | ...
B | ...
... where the plugin column would be the serialized representation of the plugin that I can deserialize back into a class. However, that seems like a terrible/hacky idea. Is there a better way to do this?

If you don't have to query database by some of the properties serialized in Plugin column, I don't see it as a terrible/hacky idea. Also...you might consider using some non-schema database like mongodb. Anyway, I would do it with serializing (probably JSON object, if I will later consume that result from javascript, or some XML if that is more appropriate for your environment).
If you want to stay with more relational approach...then you will have a table with plugin properties...with columns: UserId, PluginId, PropertyName, PropertyValue...then, table with Plugins: PluginId, PluginName, and your table with users: UserId,...and some columns for users (this is just one way to design it) The problem is if you have some plugin properties that are complex objects...in that case, you will have to serialize them into PropertyValue column...

Tables
User
-----
UserID
Name
Plugin
------
PluginID
PluginName
PlugInProperty
------------------
PlugInPropertyId
PluginID
UserPlugin
------------
UserPluginId
UserId
PluginId
UserPlugInProperty
------------------
UserPluginId
PlugInPropertyId
Value

Related

How to create one PredictEnginePool which serves multiple models?

My project is an online foods order app, the key feature of this app is the "Daily nutrients intake monitor". This monitor shows the differences of daily intake recommendation values of 30 types of nutrients vs the actual nutrients contains from the foods in user's shoppingcart.
I created 30 models base on those nutrients and each one of them has an InputData which inherits from a base class - NutrientInputDataBase, below is the example of Added sugar InputData class and the base class:
public class AddedSugarUlInputData : NutrientInputDataBase
{
[ColumnName(#"AddedSugar-AMDR-UL")]
public float AddedSugar_AMDR_UL { get; set; }
}
public class NutrientInputDataBase
{
[ColumnName(#"Sex")]
public float Sex { get; set; }
[ColumnName(#"Age")]
public float Age { get; set; }
[ColumnName(#"Activity")]
public float Activity { get; set; }
[ColumnName(#"BMI")]
public float BMI { get; set; }
[ColumnName(#"Disease")]
public float Disease { get; set; }
}
From the official documents:
https://learn.microsoft.com/en-us/dotnet/machine-learning/how-to-guides/serve-model-web-api-ml-net
i understood that i need to create a 'PredictionEnginePool' and i already know how to register the PredictionEnginePool in the application startup file.
My app logic is when user added or removed an item from the shoppingcart, the front end will request the api, the backend will get the user profile first(to obtain the input data for the prediction), then return a packaged objects which contains all 30 types of nutrients prediction results.
My question is, should i register the PredictionEnginePool for each one of the nutrient model individually in the Startup file? or in anyother effecient way which i haven't be awared of?
There's multiple ways for you to go about it.
Register each of your models PredictionEnginePool. The FromFile and FromUri methods allow you to specify a name for each of your models so when you use them to make predictions in your application you can reference them by name.
Save your model to a database as a blob. Then you can add logic on your application to load a specific model based on the criteria you specify. The downside to this is you'd have to fetch your models more dynamically rather than having a PredictionEnginePool ready to go.

Cannot read linked data from DB

I have configured this two entities:
Host.cs
public class Host : FullAuditedEntity<int>
{
[Required]
public string Name { get; set; }
public List<HostLine> HostLines { get; set; }
}
HostLine.cs
public class HostLine: FullAuditedEntity<int>
{
[Required]
public string Name { get; set; }
public Host Host { get; set; }
}
Manually, I inserted in the DB one tuple for Host and HostLine, linking them accordingly.
select Id, Name from [MyDB].dbo.Hosts;
Id | Name
-----------
1 | Host1
select Name, HostId from [MyDB].dbo.HostLines;
HostId | Name
------------------
1 | HostLine1
The HostLine's FK to the Host table is configured as you can see in the screenshot below.
Then, I implemented a simple Service which extends AsyncCrudAppService to provide CRUD operation on both the Host and HostLine entities.
public class HostsAppService : AsyncCrudAppService<Host, HostDto, int, PagedResultRequestDto, CreateHostDto, HostDto>, IHostsAppService
{
public HostsAppService(IRepository<Host> repository)
: base(repository)
{
}
protected override HostDto MapToEntityDto(Host entity)
{
return base.MapToEntityDto(entity);
}
}
I added the override to the method MapToEntityDto in order to see the data read from the DB (it will be removed).
When I call the Get REST method of the service via the Angular client I can reach the MapToEntityDto() method, but the Host entity does not have a value for the HostLines List field.
So it seems that the Host repository is not reading the linked data from the HostLine table.
Am I lacking some kind of configuration to let the Host repository read also the HostLine data?
Thank you
You need to include the HostLines manually with the below code.
public class TaskAppService : AsyncCrudAppService<Host, HostDto, int, PagedResultRequestDto, CreateHostDto, HostDto>, IHostsAppService
{
//...
protected override IQueryable<Task> CreateFilteredQuery(GetAllTasksInput input)
{
return base.CreateFilteredQuery(input).Include(x=>x.HostLines);
}
//...
}
Further information see https://aspnetboilerplate.com/Pages/Documents/Application-Services#crud-permissions

Mapping a User entity into a User DTO in .NET Core

I'm developing a web app that contains a User entity that is derived from .NET Core's IdentityUser. Lets suppose there is another entity called Comment which has a relation to a user (the user who posted the comment):
public class User : IdentityUser
{
public string SomeExtraField { get; set; }
}
public class Comment
{
//Owner (Creator) of the feedback
public User User { get; set; }
//body of the comment
public string Body { get; set; }
}
Now suppose I have an API endpoint that returns all of the comments in the system. If I query for all comments and include the User relation, when the object gets serialized, everything in the User class is serialized and sent to the client (including the users hashed password, etc). Obviously I don't want this. So I've created a CommentService layer that grabs the Comments from a CommentRepository. From my understanding, the service layer should do the job of mapping the raw Comment object into a Comment DTO, which only contains data that should be sent to the client. I've defined a comment and user DTO like this:
public class UserOutput
{
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
public class CommentOutput
{
public UserOutput User { get; set; }
public string Body { get; set; }
}
Then in my service layer I have something like the following:
//Fetch all comments
var list = await _repository.ListAsync();
//Map comments to DTO
var result = list.Select(x => new CommentOutput
{
Body = x.Body,
User = new UserOutput
{
Id = x.User.Id,
SomeExtraField = x.User.SomeExtraField,
}
});
This all seems to work great. However I can foresee one problem. Lets say I have a large system with Comments, Posts, Likes, Private Messages, etc. I can map them all in a similar fashion above. Then one day I decide to add another field to the UserOutput DTO. Now I have to go through potentially hundreds of mapping code like the sample above to map the new field properly, and whats worse is the compiler wont tell me if I've missed anything. I would like to have a function somewhere that maps a User to a UserOutput but I don't know where it should go.
I've seen some suggestions to put a constructor to the DTO that does the mapping:
public class UserOutput
{
public UserOutput(User user)
{
Id = user.Id;
SomeExtraField = user.SomeExtraField
}
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
but I've seen people against this because it tightly couples the DTO with the Entity. I've also seen suggestions of using Auto Mapper but is also seems an equal amount of people are against it.
Where should I place code that can perform these DTO->entity and entity->DTO mappings so I don't repeat myself all over the place?
Try to check out AutoMapper.
This library will help you to map the Entity Class into the ViewModel.
The way to use it is pretty straightforward.

Domain Model with partially loaded objects

Let's say I have an application which consists of both client and server. Client is using MVVM pattern (with WPF) and server is simply a WCF service which fetches some data from database and returns data as DTO-objects to client. In client, DataAccess layer converts these DTOs to domain objects and passes them to Model. ViewModel uses Model to fetch data (Domain Object) and populates itself with it.
To optimize database performance, each ViewModel is given only the data it really needs and nothing more (as recommended by many sources). For example, let's say there is an entity called DbCustomer which has 30 properties, and there are also 3 different Views related to customers: CustomerProfileView, CustomersListView and CustomerThirdView. Every view needs different portion of data: CustomerProfileView uses 20 properties, CustomersListViewuses 10 properties and CustomerThirdView uses only 4 properties. For each View, only required properties are fetched from database and delivered to ViewModel.
Now the problem arises: how should I design my Domain Objects to support this?
Solution 1, one partially loaded Domain Object (no-go)
If I have only one Customer Domain Object which is used by all ViewModels, it would have different data depending on the ViewModel that requested it. Obviously this is a no-go way because if I have to use this Customer object somewhere else I cannot be sure does it have enough properties loaded.
For example, I might have method GetDataStoragePath which is supposed to return string describing path to customer's private files. The method requires properties FirstName, LastName, SSN and IsExternalCustomer. Now, let's say CustomerThirdView doesn't need IsExternalCustomer, so it is not loaded when CustomerThirdViewModel requests Model to load Customer. Now if I use this Customer somewhere else (it is not a ViewModel specific object), the method GetDataStoragePath will fail.
Solution 2, three different Domain Objects
In another solution there would be 3 different Domain Objects (used as data containers) with suitable interfaces, and thenGetDataStoragePath would depend only from this interface. Example:
public interface ICanGetDataStoragePath {
string FirstName { get; }
string LastName { get; }
string SSN { get; }
bool IsExternalCustomer { get; }
}
public CustomerProfileData : ICanGetDataStoragePath { ... } // Implements interface
public CustomerListViewData : ICanGetDataStoragPath { ... } // Implements interface
public CustomerThirdViewData { ... } // Does NOT implement interface
public class CustomerLogic : ICustomerLogic {
public string GetDataStoragePath(ICanGetDataStoragePath customer) {...}
}
This would lead to Anemic Domain Model but it is not a problem in my opinion. However, it seems messy since I can easily imagine that there would be 20 different methods with different needs which would result in 20 interfaces (and only for Customer, there are LOTS of other domain objects also). Of course in this simple case I could pass all four parameters separately to GetDataStoragePath but in real life there are many more required properties.
Are there any other options? What would be the best way to solve the problem?
Your model obviously has to much Data. Why not make 3 models and one composite model?
i.e.
public class CustomerProfile
{
public string Phone { get; set; }
// other profile fields
}
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string SSN { get; set; }
public bool IsExternalCustomer { get; set; }
public CustomerProfile Profile { get; set; }
}
Then you'd put all of your always required fields into the Customer class and group the rest together, i.e. in a CustomerProfile class. If it's null, then that data wasn't fetched and isn't available

Entity Framework Code First, nonempty setter or getter?

I am working with an EF Code First project, and all is well. I have a simple Class, Customer. In my Customer Class I have a field I want to encrypt (Yes, I know I can encrypt at the DB level but requirements dictate I encrypt at the Domain/Code level), so I am hoping that I can do something like the following:
public class Customer
{
public int CustomerID { get; set; }
public string FieldToEncrypt { get; set { _FieldToEncrypt = MyEncryptionFunction.Encrypt(); } }
}
However, I assume that if the setter has a definition, entity framework code first may ignore that property when generating the schema. So my question is, is there a way to do EF Code First with provided getters/setters, or should I move this functionality into a constructor? Should I override one of the methods/events that happens when the Context is saving, instead?
EDIT ********************
As a note, I am using DataService to transmit the data over an OData protocol service. This automatically generates insert/update/select methods. Some of the suggestions require creating a second property, but the DataService class does not seem to pass through NotMapped properties. This throws a bit of a kink into my earlier question.
public class Customer
{
public int CustomerID { get; set; }
public string EncryptedField { get; private set; }
[NotMapped]
public string Field
{
get { return MyEncryptionFunction.Decrypt(EncryptedField); }
set { EncryptedField = MyEncryptionFunction.Encrypt(value); }
}
}

Categories