I want to allow the user to create his own entity, for example:
- Student (Name, Age, School, Photo etc.)
- Animal (Name, Type, Country etc.)
- Car (Brand, Color, Price etc.)
etc.
and then the user will be able to add records in the db according to the entity created.
All the properties will be strings.
My question is how can i save instances of these entities best in a database.
Creating a new table for each entity created i think is out of the question.
I was thinking saving in a table the properties for every entity created, and then in another table, instances of this entities, the properties will be separated be a comma for example;
Entity structure table (for student):
property_name entity_key
name student
age student
school student
photo student
Entity instances table :
instance entity_key
joe,19,nyhigh,joe.jpg student
What about the classes with whom i would create instances of these records? (?auto generated classes?) (?a class with a List property in which i would separate the 'joe,12,nyhigh,joe.jpg' string?)
Has anyone met with this type of problem before?
I will develop the application in asp.net C#.
Serialize the entity and save it in the instance column. If you need to do DB queries against the values, use XML serialization.
public static string SerializeToString(object obj)
{
using (var serializer = new XmlSerializer(obj.GetType()))
using (var writer = new StringWriter())
{
serializer.Serialize(writer, obj);
return writer.ToString();
}
}
you could make a Entity type table and a Entity property table and relate the two of them together. If all your properties are strings. If they are not you can also store type in the entity property table.
You will need to create a name value pair table and have it point to a student table
Student
ID int
FirstName nvarchar(50)
LastName nvarchar(50)
NameValue
ID int PK
Name nvarchar(50)
StudentID int FK
Value nvarchar(50)
you will find quering the database will turn into a real hassle as you will need to pivot everything out of it. But if each of your objects are truly unique then pivoting will not help.
Related
I know that my question is a bit confused, But let me explain in detail.
Suppose that I have person class like this.
public class Person {
public int Id {get; set;}
public string Name {get; set;}
}
and I want create a new entity, but these two classes are similarly so I would like to just inherit and add some new properties
public class Employee : Person {
public string Position {get; set;}
}
everything works fine, but I have a problem when I want to select the data from person table and add it to Employee class like this
employee = _context.Person.Select(
a => new Employee {
Name = a.Name,
Position = "Programmer"
}).ToList();
So as you can see here, I want to add the position property, but also want the previous data from person table. The problem is, I have to type the previous data from person table manually. If the person table has a lot of properties I need to type all of that to get all data. Is there anyway to get previous data without typing all of them. So in javascript it have something like
new State = {
...State,
Position : "employee"
}
Is it possible to do something like this in c#?
Having employee as an entity, you can use
var employees = _context.Employee.Include(e=>e.Person).ToList();
then you'll do it like this employees[0].Person.Name and so on.
If I understand you, you essentially want to "upgrade" an existing Person entity to an Employee entity. Unfortunately, this is not as simple or straight-forward as you would like. EF Core models inheritance via a single table with a discriminator column. That discriminator column informs what class type should actually be instantiated, when the entity is pulled from the database. Since it was saved as a Person, it will have "Person" as the value there, and EF Core will instantiate a Person instance when you retrieve it from the database.
You can then potentially downcast it to Employee, but EF Core isn't going to know what to do with this. Technically, the downcast instance will be untracked. If you attempt to track it, you'll get an error on saving as EF Core will attempt to add a new Employee with the same PK as an existing Person. Boom.
Your best bet is to map over the data from the Person instance to a new Employee instance, including all associated relationships. Then, create the Employee, causing the relationships to be moved at the database-level, before finally removing the old Person.
This will of course result in a new PK being assigned (which is why it's important to migrated the related entities), and that could potentially be problematic if you've got URLs referencing that PK or if you're simply dealing with an auto-increment PK. You'll end up leaving gaps in the keys, and could potentially even run out of keys, if you do this enough.
The only other potential alternative is to change the value of the discriminator column. This would have to be done via straight SQL, as the discriminator column is a shadow property not exposed by EF Core (i.e. there's no way to modify it via C# code). However, if you literally change the value to something like "Employee", then when you fetch it, EF will create an Employee instance, just will all the Employee-specific properties null or default. However, at that point, you can make the necessary updates and save it back.
In SQL, I would tell the database what the foreign key constraint is.
But fluent EF6 apparently does not have a way for me to specify what column to use when binding collections.
Is it not possible to tell DbModelBuilder exactly what column to bind relationships on? Or does it demand to be the primary key at all times?
Table_Person
id int // pkey. Multiple people records
UniqueID int // the unique person
sometext varchar(256) // database therefore tracks changes to this, since unique person can have many records (pkeys).
Table_Address
id int //pkey
fk_unique int // should map to UniqueID of person, NOT the pkey.
line1 varchar(512)
state varchar(64)
etc
One unique person has many records, and their uniqueID (not pkey) has many associated addresses. Actual structure is far more complex than that. But am looking for a way to do this fundamentally...
Would very much so like to have an ICollection<Address> Addresses within the Persons model. But to enable such a thing for code-first migrations... seems impossible?
Yes I could Add-Migration and then modify the generated code/sql manually. But doesn't that defeat the point? Or is that common practice?
If you're able to modify the DB schema you could put UniqueIDs for people into their own table named "Person" and rename the existing table to "PersonVersion". Then have FKs to the new "Person" table on "PersonVersion" and "Address". And finally, create the Person, PersonVersion, and Address models in your app code and EF should bind without problem.
Consider 3 classes: Person, Company, and File.
Person and Company are completely different and unrelated, but they each have a collection of File objects. Regardless of what entity it belongs to, File always has the same structure.
This question is about how to best model the multiple many-to-one relationships that File can have; in this case File can have a many-to-one relationship with Person or with Company (but not both in the same instance).
Approach 1:
class Person
{
public int Id {get;set;}
public ICollection<File> Files {get;set;}
}
class Company
{
public int Id {get;set;}
public ICollection<File> Files {get;set;}
}
class File
{
public int Id {get;set;}
public string Path {get;set;}
}
/*
EF Generates:
-----------------
Table: Person (Id)
Table: Company (Id)
Table: File (Id, Path, Person_Id, Company_Id)
*/
This seems the simplest and most straightforward from a code first perspective, and it's what I like best. The problem is the table File, which has null-able fields for Person_Id and Company_Id. From a DB design perspective, this seems wrong, considering that only one of the two fields will ever have a value, and the other will always be null. Adding more classes with file collections exasperates the problem even more.
Approach 2:
class Person
{
public int Id {get;set;}
public ICollection<PersonFile> Files {get;set;}
}
class Company
{
public int Id {get;set;}
public ICollection<CompanyFile> Files {get;set;}
}
class File
{
public int Id {get;set;}
public string Path {get;set;}
}
class PersonFile
{
public Person Person {get;set;}
public File File {get;set;}
}
class CompanyFile
{
public Company Company {get;set;}
public File File {get;set;}
}
/*
EF Generates:
------------------
Table: Person (Id)
Table: Company (Id)
Table: File (Id, Path)
Table: PersonFile (Person_Id, File_Id)
Table: CompanyFile (Company_Id, File_Id)
*/
This accomplishes the same thing as Approach 1, and is closer to what I have traditionally done in DB first design. But it requires two additional classes that I really don't need... or do I? I guess that's the point of this question...
When designing a Code First Entity Framework application, do I need to worry about the database schema? Can I prioritize my code/model simplicity over the database design, as in Approach 1? Or should I write classes with database design in mind, as in Approach 2?
Yes you do have to worry about the database schema,
Maybe not specifically in your example, but especially when inheritance is used.
The reason for this is because relational databases (esp. SQL) do not know the concept of inheritance. When designing your schedule you'll have to decide what approach suits your needs.
For example, when creating a school database, you'll probably design a Person, who has a name, address, telephone number, etc.
You'll find that both Students and Teachers have names, addresses etc. In contrast to popular belief you'll find that both students and teachers are persons.
Three approaches to inheritance are most used.
TPH Table per hierarchy: one big table for all derived classes of Person, with all properties of the Teachers and the Students in one table
TPT Table per type: Teachers / Students / Persons are in separate tables. Teachers and Students have a foreign key to their Person data
TPC Table per Concrete class: a Teacher table that contains all data for Teachers and the Person Properties and a Student table that contains all data for Students and Person Properties.
Whichever you'll use depends on the ratio of shared properties and the difference between Students and Teachers. If they have almost all their properties in common, then TPH with one table will be enough.
However if there are a lot of student properties that teachers don't have, then the table will have a lot of null values for teachers. If there aren't a lot of teachers compared to the number of students this might not be a problem, otherwise the waste of space might be an item to consider.
Another thing to consider is how often the scheme will change. If you really are certain that teachers will always be Persons, and that the common properties between Students and Teachers (= Person properties), will always be common, then probably TPH will be better: three tables: Persons / Teachers / Students.
On the other hand, if you think that whenever you need a student, you'll always need his Person data, then TPH will always lead to a join. Perhaps in that case TPC might be a better choice. However, if you quite often only need Student's specific data without his Person data, TPC might not be a good choice
If you don't care about the scheme, you'll find that Entity Framework will choose TPH: one big table with all students and teachers with all properties of students and teachers.
If you don't want this, you'll have to tell EF that you want one of the other approaches. This is easily done using fluent API
How this is done is fairly good described in Inheritance Strategy in Code-First
By the way, the complete article was very helpful for me to start programming using EF - code first
I need to map a standard property (string) for a class which is not available in table mapped for class but in another table.
public class Centre
{
public int ID;
public string Name;
public string DescriptionInfo;
}
Database contains two tables - one is Centre and another is InfoText.
With above case want to populate the Centre entity and filled the DescriptionInfo property from InfoText table. InfoText table might have other column on which filter needs to be applied since this table contains description for other entities.
Options available are make a view of tables or use inheritance. Don't want to use inheritance OR create view for same.
Is it possible some other to make that join and fill the description.
I'm doing an application in C# with an SQL database.
I've got a model:
Person()
{
string id;//unike key
string name;
List<string> responsableOf;//list of id
}
and I want to represent it into a table.
Which are the right fields for the tables?
It depends on what kind of relation is there between the person and the other persons that he will be responsible for.
If it is a parent and child relation i.e a composition you can use a self reference table. Something like:
Persons with the following columns:
Id,
name.
ParentId Foreign key to the same table.
If the relation between the person and the others is an aggregation, and a person may be responsible for many other persons:
Persons:
Id,
name.
usersresponsibilities:
Id,
PersonId,
ResobonsiblePersonID.
Later, in both the two cases, in your front end application you will need to deal with the data in these table as an objects not as rows. You should think in terms of objects.
In your application your current class Person should be mapped to this table.
The solution is going to depend a little on your constraints :
If a single person can have several people responsible for them
What you need is a many to many relationship between persons (and a table for the person containing the other fields, ID and name)
You would represent that using a table associating two IDs (Foreign Keys) For any given row, the table would associate :
The ID of the responsible
The ID of a person he is responsible for
Building your list is as simple as querying this table for rows with a given responsible ID.
If a single person can only have one person responsible for them
You need a Foreign Key to the same table in your Person table (Responsible ID).
Building your list is then as easy as querying the person table for rows with a given responsible ID.
create a table with id and responsableOfID as integers while responsableOfID is a foreign key to another table which has an id and name