How to remove duplicate entries in ASP.Net MVC Index View table - c#

I have the following scenario:
I have a Contact with properties FirstName and LastName. A Contact can have multiple PhoneNumbers and as many EmailAddresses. I have identified these as 3 entities with common relationships. Please see the table definitions below:
create table Contact
(
ID int primary key not null identity(1,1),
FirstName nvarchar(40),
LastName nvarchar(40)
);
go
create table ContactNumber
(
ID int primary key not null identity(1,1),
PhoneNumber nvarchar(40)
);
go
create table EmailAddress
(
ID int primary key not null identity(1,1),
EmailAddress nvarchar(40)
);
go
create table UserContact
(
ID int primary key not null identity(1,1),
ContactID int foreign key references Contact(ID),
ContactNumberID int foreign key references ContactNumber(ID),
EmailID int foreign key references EmailAddress(ID)
);
go
Now I need to display these users in a Web Application of my choice. I chose C# MVC with a Razor Engine for the View. I'm battling to model this view in a table. The table needs Action Links to edit, delete, create a new contact and view the details of the contact. I want the result set to show as below:
FirstName | LastName | ContactNumber | EmailAddress
-------------------------------------------------------
James | Smith | 082 111 5454 | james#domain1.com | edit | details | delete
| james#domain2.com
| james#domain3.com
--------------------------------------------------------
Luther | Arnolds | 082 111 5455 | luther#domain1.com | edit | details | delete
| 082 111 5456 |
--------------------------------------------------------
Sarah | Jones | 082 111 5510 | sarah#domain.com | edit | details | delete
---------------------------------------------------------
| | |
However I'm just not finding the write way to translate the ContactNumberID and EmailID columns from UserContact to map from their corresponding bridging tables. The issue that I am facing right now is that it is duplicating the records in UserContact thus making the table contain a lot of redundant data. For example the record for James Smith would be repeated 3 times. How can I achieve this in ASP.Net MVC without any duplication of entries?

I would do something like this. Notice that I changed up the column names a little bit. It is a pet peeve of mine to have a column named ID. It is a ContactID (or whatever) regardless of which table it is in. I also really dislike column names changing for the same piece of data in related tables.
create table Contact
(
ContactID int primary key not null identity(1,1),
FirstName nvarchar(40) not null,
LastName nvarchar(40) not null
);
go
create table ContactNumber
(
ContactNumberID int primary key not null identity(1,1),
PhoneNumber nvarchar(40) not null,
ContactID int not null,
constraint FK_ContactNumber_Contact_ContactID Foreign Key (ContactID) references Contact(ContactID)
);
go
create table EmailAddress
(
EmailAddressID int primary key not null identity(1,1),
EmailAddress nvarchar(40) not null,
ContactID int not null,
constraint FK_EmailAddress_Contact_ContactID Foreign Key (ContactID) references Contact(ContactID)
);
go

Related

How to access the content from DataBase, "not using the primary key"

ASP NET CORE - Using EF Core
Table:
UserBooksId - Primary Key
UserId - the userId from another table
BookId - the bookId from another table
BookToBuy - where i keep my content
NrBooksOrdered - the number of the books ordered
So I don't know how to acces the content of this table using the UserId - > BookToBuy and NrBooksOrdered or even all the Primary Keys that have this userId.
Primary Key being unique, doesn't help me to much, because in the database, the UserId can be in the database multiple times, as well the bookid.
Example:
UserBookId:0 | UserId:1 | BookId:2 | BookToBuy:Wizzard | NrBooksOrdered:2
UserBookId:1 | UserId:1 | BookId:2 | BookToBuy:Wizzard | NrBooksOrdered:6
UserBookId:2 | UserId:1 | BookId:3 | BookToBuy:LongRoad | NrBooksOrdered:1
As you can see the UserId doesn't change.
Thank you.
You can use basic linq queries here
/* b is a reference here to every book, so you can filter it by the bool-expression */
var booksQuery = dbcontext.BooksTable.Where(b => b.UserId == 1 && b.BookId == 2);
/* books will be type of IQueryable so it isnt retrieved from the database */
/* yet. To do so, you can use `.ToList()` or `.AsEnumerable()` (wich is */
/* faster in use-cases, where you need to iterate the result once) */
var booksFromDb = booksQuery.AsEnumerable();
For a detailed description, on how to query data with EF-Core you can always refer back to: MS-Docs Querying Data

ORACLE: Use static value when defining foreign key constraint

How can I define a foreign key constraint like this in ORACLE:
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY ("StoreTable", STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
/
I want to combine all Enum values of several tables in one table.
In order to create a foreign key I need also to check the type of the enum since the value alone is not unique.
I need it like this so I can define the Store_Type as enum (C#) in my program but at the same time I want to make sure the database values are all valid.
For example:
TEST_STORE table:
| ID | ... | STORE_TYPE
|-----------|------------|------------
| 324234 | | 0
| 324235 | | 0
| 324236 | | 1
TEST_ENUMERATIONS table:
| ID | TABLE | VALUE | NAME
|-----------|--------------|------------|-------------
| 567234 | StoreTable | 0 | NormalStore
| 567235 | StoreTable | 1 | SpecialStore
| 567236 | AnotherTable | 0 | AnotherType
Try creating a virtual column on TEST_STORES whose value is always 'StoreTable', and use the virtual column as the first column in the foreign key.
ALTER TABLE TEST_STORES ADD (ENUM_TABLE AS 'StoreTable');
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY (ENUM_TABLE, STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
Seems that you need:
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY (NAME, STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
/
You will need a unique key on test_enumerations(table,value) as well.

Combining Characters with Id Field

I'll create an Issue table in an MVC5 application and I want to use special code for each type of the issues as below:
For IT related questions INF-0001, INF-0002, ...
For General type of questions GEN-0001, GEN-0002, ...
As I use all the issues on the same table, I think it is better to store the ID numbers as INF-0001, GEN-0001, ... etc. In that case should I use string as the data type of ID column in MSSQL? Or what is the best approach in order to store Id's with their related codes? I also think of using GUID, but I am not sure if it is possible. Thanks in advance.
I suppose it's better create separate field for your custom names. So your table will have int Id (Primary Key) field and CustomName varchar(100) or nvarchar(100) type (If you use unicode characters) field with your custom names.
It will be better for perfomance to use int as Id if you will JOIN your file table with others. If you want to search values in this field and it is slow just create INDEX.
You could have a general issue id and a category, for example:
Table: Issue
------------------------------------
IssueID | CategoryID | CategoryIndex
------------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 1 | 3
Table: Category
-----------------------------
CategoryID | Prefix | Name
-----------------------------
1 | INF | IT
2 | GEN | General
Then you calculate the issue number when querying these tables.
You can store the calculated number in a table if you want to keep track of the issue number in case of a change in the database (ex: the prefix for IT related questions changes from INF to IT)
Now that you have a good schema, how do you keep control of the category sequence on the issues table? Check this out:
DECLARE #categoryID INT
DECLARE #nextSequence INT
SET #categoryID = 1 --You'll have to change this!
SELECT #nextSequence = i.CategoryIndex
FROM Issue i
WHERE i.CategoryID = #categoryID
SELECT COALESCE(#nextSequence, 0) + 1 as 'NextSequence'
You can turn that into a stored procedure (NextSequence, maybe?) that receives an INT as parameter (the category ID) and returns another INT as result (the CategoryIndex for the new issue).
Finally, to create your full code:
SELECT
i.IssueID
, c.Prefix + '-' + RIGHT('0000' + CONVERT(VARCHAR(4), i.CategoryIndex), 4) as 'IssueCode'
FROM Issue i
INNER JOIN Category c ON i.CategoryID = c.CategoryID

Fluent NHibernate: Cascade delete from one side only on Many-to-Many relationship

I'm trying to write the proper map configuration that will allow me to delete from only one side on a Many-to-Many relationship setup.
Below is the code structure for my Map and Entity class along with the actual program (psuedo) code and SQL schema. Fairly simple and straight forward.
We have a person table, and a file table. We then have a personfile table since a person can have many files and likewise, a file can be assigned to many persons.
Now, when I delete a person record, the related records in personfile and file belonging to the person are deleted. So far so good.
If I delete a file (as shown belowin Program.cs), I want it to delete from personfile and file but NOT from person.
However with the way I have things setup, NHibernate only calls the delete on file table which causes an error. Eg.
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`personfile`, CONSTRAINT `FK_PersonFile2` FOREIGN KEY (`FileID`) REFERENCES `file` (`FileID`))
I did add Cascade.Delete() to FileMap but when i did that, deleting from file table also deletes from person table.
To reiterate, what I ultimately want is to call Delete(file) which in turn will delete the records from personfile table and file table but NOT person table.
Should I instead be going the route of getting the person record and then removing the file record from person.Files[] collection and then calling SaveOrUpdate()?
Consider the scenario.
First make sure we have good data in all tables.
mysql> SELECT f.FileID, p.PersonID, p.Name, f.Filename
-> FROM personfile pf
-> LEFT OUTER JOIN file f on pf.FileID = f.FileID
-> LEFT OUTER JOIN person p on pf.PersonID = p.PersonID
-> ;
+--------+----------+------+-------------+
| FileID | PersonID | Name | Filename |
+--------+----------+------+-------------+
| 1 | 1 | John | Apples.jpg |
| 2 | 1 | John | Oranges.jpg |
| 3 | 2 | Bob | Grapes.jpg |
+--------+----------+------+-------------+
3 rows in set (0.00 sec)
Now in a normal situation if you try to delete file only (which is what NHibernate is trying to do based on my setup) this is what happens which is expected.
mysql> DELETE FROM file WHERE file.FileID = 2;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`pe
rsonfile`, CONSTRAINT `FK_PersonFile2` FOREIGN KEY (`FileID`) REFERENCES `file` (`FileID`))
What I want NHibernate to do is something like this, where first the records in the relation table is deleted then the record in the atual file table.
The query doesnt' have to be specific, as long as the end result is same.
mysql> DELETE pf, f
-> FROM personfile pf
-> LEFT OUTER JOIN file f on pf.FileID = f.FileID
-> LEFT OUTER JOIN person p on pf.PersonID = p.PersonID
-> WHERE pf.FileID = 2
-> ;
Query OK, 2 rows affected (0.05 sec)
The result of the above delete is valid.
mysql> SELECT f.FileID, p.PersonID, p.Name, f.Filename
-> FROM personfile pf
-> LEFT OUTER JOIN file f on pf.FileID = f.FileID
-> LEFT OUTER JOIN person p on pf.PersonID = p.PersonID
-> ;
+--------+----------+------+------------+
| FileID | PersonID | Name | Filename |
+--------+----------+------+------------+
| 1 | 1 | John | Apples.jpg |
| 3 | 2 | Bob | Grapes.jpg |
+--------+----------+------+------------+
2 rows in set (0.00 sec)
Program.cs
File file = db.Session.Load<File>(2);
session.Delete(file);
transaction.Commit();
Mapping
public class FileMap : ClassMap<File>
{
public FileMap()
{
Id(x => x.FileID)
.GeneratedBy.Identity();
Map(x => x.Filename)
HasManyToMany(x => x.Persons)
.Table("PersonFile")
.Inverse()
.ParentKeyColumn("FileID")
.ChildKeyColumn("PersonID");
}
}
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.PersonID)
.GeneratedBy.Identity();
Map(x => x.Name)
HasManyToMany(x => x.Files)
.Table("PersonFile")
.Cascade.Delete()
.ParentKeyColumn("PersonID")
.ChildKeyColumn("FileID");
}
}
Entity
public class File
{
public virtual uint FileID { get; set; }
public virtual string Filename { get; set; }
public virtual IList<Person> Persons { get; set; }
}
public class Person
{
public virtual uint PersonID { get; private set; }
public virtual string Name { get; set; }
public virtual IList<File> Files { get; set; }
}
SQL
CREATE TABLE `file` (
`FileID` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`FileID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `person` (
`PersonID` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`PersonID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `personfile` (
`PersonID` int(11) unsigned NOT NULL DEFAULT '0',
`FileID` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`PersonID`,`FileID`),
KEY `FK_PersonFile2` (`FileID`),
CONSTRAINT `FK_PersonFile1` FOREIGN KEY (`PersonID`) REFERENCES `person` (`PersonID`),
CONSTRAINT `FK_PersonFile2` FOREIGN KEY (`FileID`) REFERENCES `file` (`FileID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Try calling File.Persons.Clear() to remove the linked Persons from a File before deleting it.
I'm curious about this requirement; the 2nd sentence seems to contradict it because you could delete File records that are linked to a different Person than the one you're deleting.
We have a person table, and a file table. We then have a personfile table
since a person can have many files and
likewise, a file can be assigned to
many persons.
Now, when I delete a person record,
the related records in personfile and
file belonging to the person are
deleted. So far so good.
File.Persons.Clear();
Session.Flush();
Session.CreateQuery("delete from File").ExecuteUpdate();
Works for me!

How to get rid of multiple columns in a database?

I'm creating an Access DB for use in an C# application at school. I've not had much experience working with DB's so if this sounds stupid just ignore it. I want the user to be able to select all the classes that a certain student has had in our IT department. We have about 30 in all and the maximum that a person can take in 4 years of high school is 15. Right now my DB has 15 different columns for each class that a user could have. How can I compress this down to one column (if there is a way)?
Excellent question Lucas, and this delves into the act of database normalization.
The fact that you recognized why having multiple columns to represent classes is bad already shows that you have great potential.
What if we wanted to add a new class? Now we have to add a whole new column. There is little flexibility for this.
So what can be done?
We create THREE tables.
One table is for students:
Student
|-------------------------|
| StudentID | Student_Name|
|-------------------------|
| 1 | John |
| 2 | Sally |
| 3 | Stan |
---------------------------
One table is for Classes:
Class
------------------------
| ClassID | Class_Name|
------------------------
| 1 | Math |
| 2 | Physics |
------------------------
And finally, one table holds the relationship between Students and Classes:
Student_Class
-----------------------
| StudentID | ClassID |
-----------------------
If we wanted to enroll John into Physics, we would insert a row into the Student_Class table.
INSERT INTO Student_Class (StudentID, ClassID) VALUES (1, 2);
Now, we have a record saying that Student #1 (John) is attending Class #2 (Physics). Lets make Sally attend Math, and Stan attend Physics and Math.
INSERT INTO Student_Class (StudentID, ClassID) VALUES (2, 1);
INSERT INTO Student_Class (StudentID, ClassID) VALUES (3, 1);
INSERT INTO Student_Class (StudentID, ClassID) VALUES (3, 2);
To pull that data back in a readable fashion, we join the three tables together:
SELECT Student.Student_Name,
Class.Class_Name
FROM Student,
Class,
Student_Class
WHERE Student.StudentID = Student_Class.StudentID
AND Class.ClassID = Student_Class.ClassID;
This would give us a result set like this:
------------------------------
| Student_Name | Class_Name |
------------------------------
| John | Physics |
| Sally | Math |
| Stan | Physics |
| Stan | Math |
------------------------------
And that is how database normalization works in a nutshell.
So you have 15 columns (e.g. class1, class2, class3 ... class15)?
Looks like you have a classic many-to-many relationship. You should create a new table to relate students and classes.
student { StudentID, StudentName ... }
classes { ClassID, ClassName ... }
student_classes { StudentID, ClassID }
If you are tracking classes on a year-by-year basis, you could add a year column to the relationship as well:
student_classes { StudentID, Year, ClassID }
It sounds like you need to think about normalizing your database schema.
There is a many-to-many relationship between students and classes such that many students can take many classes and many classes can be taken by many students. The most common approach to handling this scenario is to use a junction table.
Something like this
Student Table
-------------
id
first_name
last_name
dob
Class Table
-----------
id
class_name
academic_year
Student_Class Table
-------------------
student_id
class_id
year_taken
Then your queries would join on the tables, for example,
SELECT
s.last_name + ', ' + s.first_name AS student_name,
c.class_name,
sc.year_taken
FROM
student s
INNER JOIN
student_class sc
ON
s.id = sc.student_id
INNER JOIN
class c
ON
sc.class_id = class.id
ORDER BY
s.last_name, sc.year_taken
One word of advice that I would mention is that Access requires you to use parentheses when joining more than table in a query, I believe this is because it requires you to specify an order in which to join them. Personally, I find this awkward, particularly when I am used to writing a lot of SQL without designers. Within Access, I would recommend using the designer to join tables, then modify the generated SQL for your purposes.
This is a normalisiation issue. In effect you are asking the wrong question. In stead ask yourself the question how can you store 0 or more classes_taken? What other details do you need to store about each class taken? E.g. just the class taken, or data taken, result, etc?
For example consider somethin like the following
table Student
id int
name varchar(25)
...
table classes
id int
name varchar(25)
...
table clases_taken
student_id int (foreign key to student.id)
class_id int (foreign key to class.id)
data_started datatime
result varchar(5)
tutor_id int (foreign key to tutor.id)
...
You should never have columns like class1, class2, class3, class4 etc in a database table. What you should have is a related table. Your stucture would be something like:
Student Table with the following columns
StudentID
StudentLastName
StudentFirstName
(and so forth for all the data to describe a student)
Then
Course table with the following columns
CourseId
CourseName
Then
StudentCourse Table with the following columns
StudentId
CourseID
CourseDate
Now to find out what courses the person took you join these tables together.
Something like:
Select StudentID,StudentLastName,StudentFirstName, CourseName, CourseDate
from Student
join StudentCourse on student. studentid = StudentCourse.StudentID
join Course on Course.courseID = StudentCourse.CourseID
Please read this link to start learning database fundamentals:
http://www.deeptraining.com/litwin/dbdesign/FundamentalsOfRelationalDatabaseDesign.aspx
How about no class columns in the student table. Setup a new table with student id and class id columns. Each row represents a class the student took. Maybe add more columns such as: the year/semester, grade, etc.

Categories

Resources