C# MVC - Dynamic database architecture - c#

I have an idea for a web app where I will want the user to create their own database through a web application, with their own table names and field types.
I thought about creating a database structure using Object Oriented Programming so that a pre-made database will support all kinds of Entities with custom properties. Something like this:
CustomType
{
public long TypeId {get;set;}
public string ActiveType {get;set;}
}
CustomProperty
{
public int wholeNumber {get;set;}
public string text {get;set;}
public bool boolean {get;set;}
public decimal dec {get;set;}
//Choosen Id of the type to work with
public long TypeId {get;set;}
public bool wholeNumber_ACTIVE {get;set;}
public bool text_ACTIVE {get;set;}
public bool boolean_ACTIVE {get;set;}
public bool dec_ACTIVE {get;set;}
}
CustomEntity
{
public string TableName {get;set;}
public CustomProperty Prop01 {get;set;}
public CustomProperty Prop02 {get;set;}
public CustomProperty Prop03 {get;set;}
public CustomProperty Prop04 {get;set;}
public CustomProperty Prop05 {get;set;}
}
The idea behind this is to let the user decide what they want their database to store, on a pre-made database for them to work with, without having to create it during runtime since this is a web app.
I believe I can manage it like this for them to store whatever they need, but I'm also thinking about the following issues:
How will I manage relationships when the user needs to link tables with Ids and foreign keys.
(I though about managing a public long ForeignId {get;set;} and just store the Id they need to associate).
How will I manage queries since tables will have CodeNames and each will have a different meaning for each person that sets it up.
(I though about, renaming the table during Runtime, but I'm afraid of errors and DB corruption).
Also thought about sending direct queries to create the database according to user's need, but then again non-experienced users can really mess up here or find it hard to manage.
How can I manage migration or DB changes with code instead of the use of PowerShell console.
If we have multiple users each with a unique database, but the same web app how can we manage webconfigs to work with this idea.
I know there's a lot of questions here, I'm looking for the best way to achieve this, having multiple users own their small web app through the internet using MVC pattern and lots of options through a browser.

I would recommend an Entity Attribute Value (EAV) pattern as a solution. With the EAV pattern, rather than creating new tables with new columns for every custom property you wish to store, you store those properties in rows. For example. Instead of every custom table being defined like this:
You define them like this instead:
This allows for flexible creation of multiple entities with multiple properties. The classes in your business logic will then be Entity classes with a collection of Property objects.
In case you haven’t spotted the trade-offs already, the limitation of using the EAV model is the inability to specify field types (int, varchar, decimal etc.), infact, all your property values will be stored as a single type (usually strings).
There are a number of ways to address this. Some handle all the validation etc. in the business logic, other create Field tables per type, so based on my example, rather than having just one EntityFields table, you’ll have multiple, separated by type.

Related

Xamarin SQLite using LINQ

I got a sqlite table in xamarain (native android / pcl):
[Table("Customer")]
public class Customer
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public Address Address{ get; set; }
}
"Address" represents a second table.
1) Is it possible to automatically create the "Address" Table when I call
connection.CreateTable<CustomerDto>();
because it is it's dependency?
2) Is it possible to use a LINQ expression which automatically maps the correct "Address" to this "Customer?
In my .NET Standard library I'm using:
"sqlite-net": "1.0.8"
"sqlite-net-pcl": "1.3.1"
My approach was to create "initial state models" of all the tables, marked as abstract (so there is no risk that somebody could instantiate them), defining only the fields necessary in the database and the primary keys (GUID in my case), used only to create tables at the beginning. Following modification to the data structures always with ALTER instructions.
In another namespace a duplication of all the models, this time with getters/setters and other utilities, and I used these as "real models".
For representing linked models I used a field as Id and another one as model (refreshed when necessary):
public int IdAddress { get; set; }
[Ignore]
public Address Address { get; set; }
I don't think sqlite-net can do what you are asking because it's a very lightweight orm, and even if it could I prefer don't automate too much because of my past experiences with Hibernate.
https://github.com/praeclarum/sqlite-net
https://components.xamarin.com/view/sqlite-net
It sounds like you should look at using Entity Framework because that will allow you to use LINQ with SQLite. The standard library on the web (not Entity framework) is very light and doesn't have much functionality for the ORM like functionality you are looking for.
If you're looking for a more lightweight library, you can use this, but it will not allow you to write LINQ expressions without writing your own ORM:
https://github.com/MelbourneDeveloper/SQLite.Net.Standard

Is it a good idea to store classes as settings items in sql?

I am doing this project in c# and when designing a database, i am using a rule that each class is basically sql table (at least the class that has to be persisted).
Since some classes are purely used to define business settings and the classes are rather flat, I am curios does it make any sense to do something like this..
Transform business layer class
class Contact
{
public string Name {get;set;}
public string PhoneNumber {get;set;}
public bool AcceptsTextMessages {get;set;}
public bool AllowedHoursForTextMessagesStart {get;set;}
public bool AllowedHoursForTextMessagesEnd {get;set;}
public List<DayOfWeek> SendMessagesOnlyOnWorkdays {get;set;}
}
to a data layer class that look something like (and persist it in sql)
public Settings
{
public ID {get;set}
public Name {get;set}
public Value {get;set;}
}
with real life data
ID Name Value
1 Name John Doe
2 PhoneNumber 01234657
3 ExceptsTextMessages true
4 AllowedHoursForTextMessagesStart 0
5 AllowedHoursForTextMessagesEnd 24
6 SendMessagesOnlyOnDays 1,2,3,4,5
The primary reason for this is to have one settings table instead of having as many tables as classes, possibly easier class modification, easier manipulation of properties between classes (in case there is a business logic need to move one property from one class to another)
Decomposing your objects into IDs and attribute-value pairs is one of those techniques that's sometimes extremely useful. EAV data is much more complicated to manage than a flat table with individual columns, so it's not something to implement lightly.
Given what you've posted, I probably wouldn't. All the fields you have seem reliably relevant to being-a-contact and unlikely to require changing around dynamically in production (since one starts or stops accepting text messages, rather than ascending to a plane of existence where text messages are epistemologically irrelevant).
Even if it made sense to represent certain fields as pairs, I'd only do it for those fields: keep a users table with a primary key and the essential data, then put the rest off in an EAV table with a foreign key relationship to users.

Bindable indexed in-Memory Data Scturcture

I want to improve one of my current applications that uses ADO Data Sets. The application is standalone, no DBs. Almost everyone says that ADO Data set is an old stuff and a much better approach is using your own structures. For example I have the data model below (the same kind of model we usually use with Entity Framework):
public class Customer
{
public int ID {get;set;}
public string Value {get;set}
public IEnumerable<Order> Orders {get;set;}
}
public class Order
{
public int ID {get;set;}
public string Value {get;set}
public Customer Customer {get;set;}
}
I don't understand the next:
How to store class model in memory. Just in a simple List<>. It is not efficient with searching. In SQL we can make indexes for two often used columns and optimize our search. Can we do something similar (fast indexed search by multiple columns) in memory? If can, please explain me how. In DataTables we can use Primary Key as index.
Is a good data structure exist. A structure that allows binding to DataGrids, Fast indexed search by multiple columns, LINQ. Or we need to store everything in List<> or Hashset<> and prepare some additional structures for fast searching.

Map queries to multiples entities with Database First EF5 and view them in a DataGrid

I'm doing my first steps with Database First EF5 and I'm trying to reproduce my knowledge from the classical DataTable, DataAdapter, etc.. in EF5 ORM paradigm but I'm stuck:
I use to work a lot with DataGridsViews and Trees and fill them with Stored Procedures. The information that I use to display correspond with more than 1 table/entity.
For example, supposing a blog app. with posts, users, etc. like this:
Tables:
Post {Id, Subject, Body, Date, Author}
User {Id, Name, Email, Pwd}
And for joining all the tables and calculating some values we have an StoredProcedure. This SP returns attributes from Post and User tables and 2 run-time calculated values:
Post.Subject, Post.Body, Post.Categories, User.Name, DaysSincePublished, IsAuthorOnline
Or to make it easier:
Post.*, User.*, DaysSincePublished, IsAuthorOnline
Questions:
Is it possible to fit the previous record set in a multiples entities at once (Post and User)? And fill with it a DataGridView?
Is it possible to fit it in a entity created on-the-fly? And in that case is it possible to update (bind) it form the DataGridView.
Am I doing a wrong approach to the problem?
I have tried methods like Context.ObjectContext.Translate<TEntity>() or Context.Database.SqlQuery<TEntity>(storedProcedure, parameterArray); but only returns 1 entity at time.
Note:
With this example is it possible to forget about the StoredProcedure and make a linq query. But in the real scenario I have queries with more than 10 tables, and sub-queries, few times without FK, ... and caring a lot about server performance the stored procedure is a Must.
Well, your question is quite vague, anyway...
To use correctly an ORM, like EF, I think it's a good thing to understand as well SQL world than object world.
So, let's say you have two classes corresponding to your tables :
I imagine that you will use Database first, not Code First or Model First.
When using EF, classes will be generated from your db.
something like that :
public partial class Post {
public int Id {get;set;}
public string Subject {get;set;}
public string Body {get;set;}
public DateTime Date {get;set;}
//etc.
public virtual User Author {get;set;} //this is what's called a Navigation proeprty, which will help you to find relations with your User class.
}
public partial class User {
public int Id {get;set;}
public string Name {get;set;
public IList<Post> Posts {get;set;}//Navigation property from User to Post class. It's a list, reflecting the one-to-many from Post to User.
}
Now, for calculated properties, you can do this in a few ways.
One would be to create another part of the partial class Post
public partial class Post {
public int DaysSincePublished {get {return (DateTime.Now - Date).Days;}}
}
Then, you can use a simple query like that, saying you have
public DbSet<User> Users {get;set;}
public DbSet<Post> Posts {get;set;}
Then
var myQuery = context.Users.Include(m => m.Posts);
var list = myQuery.ToList();//this will get data from your db.
in list, you've got all the fields you need, including the "calculated properties" (well, you've got all from Post and User, which maybe more than what you really need, in fact).
To avoid retrieving all, you may use select data in an anonymous type (or a custom class)
var myQuery = context.Posts.Select(m => new {
subject = m.Subject,
body = m.Body,
userName = m.User.Name,
daysSincePublished = SqlFunctions.DiffDays(m.Date, DateTime.Now)//see another way to get calculated value
});
var list = myQuery.ToList()//retrieving only the required fields from db.
And the argument of "my real needs are too complicated for an ORM" doesn't make that much sense. Anyway, you will still be able to use SP when needed, or even raw sql. The goal is too be pragmatic, but investigate a little bit before coming to a definitive conclusion;)

How to expose calculated data of an entity through WCF

We’re developing an N-tier architecture application using WCF between client (presentation) and server (data/business layer). To be honest I can’t find any real examples/info of how to expose efficiently calculated data through WCF.
For describing my problem say we have ATM machines which have lots of transactions. So we have an 1-N relation between ATM Class and Transaction class. ATM Class has properties like Location, ModelNo, Description, InstallDate and the Transaction records have info like Amount, DateTime, CustomerInfo, TicketPaperLength, ElectricityUsed
Exposing these classes through WCF is not the issue. Problem is that we have lots of calculated fields for ATM that are based on the underlying Transaction table. For example, the client application uses reports based on the calculated data of ATM. Examples of calculated data of ATM could be: AverageTicketPaperLength, AverageAmount, DeviationAmount, AverageElectricity, etc, etc. There are lots and lots of these calculated data. The calculations should take place on the server and not on the client-side. If these report definitions were all fixed it wouldn’t be that big a problem: we could create separate services/Poco’s, for the reports. Put the calculations in a business layer and fill the Poco as needed. But the client application must have the ability to make reports filtered on whatever set of calculated properties of ATM and return as data another set of (calculated) properties.
I could create a Poco with about 500 calculated properties where there for each single report only may be 10 properties would be used. But of course we don’t want all 500 calculations executed every time for each and every entity.
So in general I’m wondering how one would expose calculated data of an entity through e.g. WCF. Almost all examples I see explaining Entity Framework, Poco and WCF only deal with the persistent fields of the entity and that is pretty straight-forward.
Do not expose entities through WCF, create some DTOs.
For example:
In wcf layer -
DtoInfoForReport1 GetInfoForReport1(long atmId) { ... call BL here... }
DtoInfoForReport2 GetInfoForReport2(long atmId) { ... call BL here... }
In data layer -
AtmEntity
{
long Id {get;set;}
... some properties ...
HashSet<Transaction> AtmTransactions {get;set;}
}
Transfer objects -
DtoInfoForReport1
{
long AtmId {get;set;}
XXX SomeCalculatedValue {get;set;}
}
In BL -
DtoInfoForReport1 CreateInfoForReport1(long atmId)
{
var atm = YYY.GetEntity<AtmEntity>(atmId);
return new DtoInfoForReport1
{
AtmId = atmId,
SomeCalculatedValue = DoSomeCalculationOverMyAtmWithItsTransactions(atm),
};
}
Hope I got your question right. Otherwise comment.
Edit based on comment:
Than I would suggest DTOs like this:
[DataContract]
public DtoRequestedCalculations
{
[DataMember]
public long AtmId {get;set;}
[DataMember]
public List<DtoRequestedCalculationEntry> Calculations {get;set;}
}
[DataContract]
public DtoRequestedCalculationEntry
{
[DataMember]
public string / long / Guid / XXX ParameterIdentifier {get;set;}
[DataMember]
public double/ DtoParameterCalculatedValueBase {get;set;}
}
Now if your calculated value is always double it's basically done. If your values may be or different types you will need some base class - DtoParameterCalculatedValueBase, which is sth like this:
[DataContract]
[KnownType(typeof(DtoParameterDoubleCalculatedValue))]
[KnownType(typeof(DtoParameterXXXCalculatedValue))]
public DtoParameterCalculatedValueBase
{
...whatever common part there may be or nth...
}
public DtoParameterDoubleCalculatedValue : DtoParameterCalculatedValueBase
{
[DataMember]
public double Value {get;set;}
}
public DtoParameterXXXCalculatedValue : DtoParameterCalculatedValueBase
{
[DataMember]
public XXX Value {get;set;}
}
Note the KnownType attribute - it tells WCF what types may come in place of base class. You will have to provide this attribute for each inherited type (or use DataContractResolver, which is already another story).
Than in WCF:
DtoRequestedCalculations GetCalculatedValuesForAtm(long atmId, List<long / string/ Guid / XXX> valueIdentifiers);

Categories