SQL Server foreign key ID and entity property - c#

For school I'm working on a project in C# WPF and SQL Server. I made the database and use Linq to SQL. Now I got the following tables:
Patients
-------
ID int PK
name varchar
insurancecompany int FK
Insurancecompanies
-------
ID int PK
name varchar
insurancecompany in patients is a FK to id in insurancecompanies
I left out a lot of unnecessary columns for my question since it would take too long. So I added the database tables to my Linq to SQL database model. I created an instance to the patient class. Looking at it, I see 2 properties. One is insurancecompany, which is an int. The other is insurancecompany1, which is an insurancecompany type.
Is it safe to make the int private, or remove it? Or is there a way to make it so there's only one property?

What is happening is that database model sees that you have a foreign key relationship to Insurancecompanies, it looks at the value you've assigned it and then finds that insurancecompany and adds it as an additional property which it calls "insurancecompany1" (it would have called it "insurancecompany" but couldn't because you already have a property with that name).
This is a nice feature because it makes it easy to look at the insurance company for a given patient without needing to use joins;
var dave = patient();
//assign a patient from your database to "dave" here..
var nameOfDavesInsuranceCompany = dave.insurancecompany1.name;
If you remove the int insurancecompany you will loose this feature because the model would no longer be able to work out which insurance company to look at. You could make it private but you would loose the ability to assign an insurance company to patient by simply giving an int value (you would always have to set an insurancecompany object to insurancecompany1).
If you don't like the names, you could rename insurancecompany to something like insurancCompanyId and then call insurancecompany1 insuranceCompany.

Related

C#/.NET inheritance best practice

I am wondering what the best practice is on a database schema for inheriting from a base class where the base class has the PK id.
Let's say I'm building an app for a school. There are Teachers and Staff each with their own "duties". I want an Employee base class. Then, I want ONE Duty class that can be for any type of employee. Meaning, I don't want to create a TeacherDuty class with a FK to the TeacherId and a second StaffDuty class with a FK to StaffId, I'd like one Duty class, bound to the EmployeeId.
What is best practice here? Or is it best practice to have a TeacherDuty and StaffDuty class with FK's to each of their respective classes. I'm trying to minimize the number of classes and make them as reusable as possible (for instance, if there's another type of Employee, like Administrator, I want to avoid creating yet another table for AdministratorDuty).
public class Employee
{
public string Id {get; set;}
}
public class Teacher: Employee
{
public string Id {get; set;}
}
public class Teacher: Employee
{
public string Id {get; set;}
}
public class Duty
{
//what's the FK here?
}
Your hierarchy still doesn't quite make sense because you have a Teacher class there twice identically. I assume one of them is meant to be Staff instead of Teacher. But even with that, I'm not quite sure why Teacher would not be considered staff also?
It's important to properly designing your schema before continuing. I'll attempt to answer you actual question, but that doesn't mean this is necessarily the correct way to go about it. I've proposed an alternative schema design at the end for you to consider.
Answering your Question
To answer your question, we can look at how ORM's (Namely Entity Framework Core) solve this kind of thing. The issue is, the concept of OOP and classes doesn't fully map over to the Relational database world. C# ORM's like Entity Framework have to do this so even if you're not going to use Entity Framework, looking at how they solve this issue can give you insight.
To make it more obvious what is going on, I'm going to add some fake columns to each your classes. Let's pretend this is what your C# classes look like:
public class Employee
{
public string Id { get; set; }
public bool IsActive { get; set; }
}
public class Administrator : Employee
{
public string PhoneNumber { get; set; }
}
public class Teacher : Employee
{
public string HomeRoom { get; set; }
}
So you can see both Administrators and teachers should share an Id and whether they are active or not. Administrators store their phone number, and teachers need a home room. Administrators do not need a home room and teachers do not need a phone number. Again, the columns aren't meant to be a real use case, just as an example.
Table per Hierarchy
The first way (and recommended/default way in Entity Framework Core) is to do a single table per Hierarchy. This means you would have a table called Employee, and that table would have all the columns required to represent every type of employee (Staff, Teacher, Administrator, etc). This means there would be 1 EmployeeID column to represent all employees. The magic comes from having a 'Discriminator' column to specify 'This employee is a X'.
So your Employee table would look something like this:
Column
Type
Id
NVARCHAR(50) PK
Discriminator
NVARCHAR(100) (NOT NULL)
IsActive
BIT (NOT NULL)
PhoneNumber
NVARCHAR(50) (NULLABLE)
HomeRoom
NVARCHAR(50) (NULLABLE)
And the data might look something like this:
Id
Discriminator
IsActive
PhoneNumber
HomeRoom
1
Teacher
1
NULL
2A
2
Administrator
1
3256-6986
NULL
In this situation your duty table would have a FK of EmployeeID, which would join to this table. Conceptually it's simple, but you have to make sure you always add the discriminator when doing queries for a specific type. Using EF Core, this is mostly handled for you.
If you wanted to query out all the Teachers, you'd do a query something like this:
SELECT * FROM Employee WHERE Discriminator = 'Teacher'
The reason this is the default way in EF Core is because it allows for faster querying of data. Everything about this 1 type is stored in the one table. That benefit is also one of its weaknesses. You can see that a Teacher row has to store that it's PhoneNumber is null, even though that data is not relevant to a teacher. This is okay in this small sample, but if you have a bunch of employee types that each have a lot of unique columns, you add a lot of bloat to your table. This can make it hard to understand what it going on.
Table-per-type
The second way to do it is by doing a table per type. In this way, you'd have an Employee table with just Id and IsActive. Then there'd be a separate table for Teacher/Administator which holds the specific data for those classes.
The schema's might look something like this:
Employee
| Column | Type |
|---- |-------|
| Id | NVARCHAR(50) PK Identity |
| IsActive | BIT (NOT NULL) |
Administrator
| Column | Type |
|---- |-------|
| EmployeeId | NVARCHAR(50) PK |
| PhoneNumber | NVARCHAR(50) (NULLABLE) |
Teacher
| Column | Type |
|---- |-------|
| EmployeeId | NVARCHAR(50) PK |
| HomeRoom | NVARCHAR(50) (NULLABLE) |
It's a bit harder to show what the data would look like, but essentially you'd have every employee inside the employee table. Then if they were a teacher, there would be a record in the Teacher table with a matching EmployeeId.
So if you wanted to query out all the teachers with this method, you'd do something like this:
SELECT * FROM Employee
INNER JOIN Teacher ON Teacher.EmployeeId = Employee.Id
The benefit to this way is that you aren't storing any wasted data.
The downside is that you could potentially make your queries a lot more complex by adding in a lot of joins. In the EF Core docs they mention this performance hit.
Alternative
I mentioned at the start that I would try to answer your question as is, which I have done. But I also think it's important to offer alternatives that may or may not apply. To me it seems like you're starting with an OOP approach to how you want your data to look, and then you're asking 'How can I map this to a database'. An OOP design doesn't really work 100% with schema's though, so instead start with a schema, then figure out how to represent that with classes.
Consider the following: Is it ever possible for an employee to have multiple roles? With your current system, someone is locked into being 1 type of employee. What if someone changes roles? Maybe they started as an Administrator but changed to a teacher? I'm not saying this is definitely an issue. Maybe you'd consider someone changing jobs a new employee, in which case your current way would work.
I'd propose structuring it completely differently though. Have your Employee table contain all the information all employees could need (no matter what role they have). Then have a separate table called something like Role, which has a row for all the different types of employees possible. For example it'd have a row for 'Teacher', 'Administrator', 'Grounds Keeper', etc. This way adding new roles is as easy as adding a row into a table.
Then you'd have a many-many table called EmployeeRole, which just stores an EmployeeID and RoleID (And maybe an IsActive to say if they are still in that role). That way a single employee can have multiple roles, and you'd have a history of their previous roles they've had before.
Then you could have your Duty table have a FK to this EmployeeRole table, instead of directly to the Employee table. Each Role the employee has would then have a different set of Duty's.
I'm not a Database designer though and this design is definitely not without its own flaws, so think about your use case and carefully design what limitations you need to allow for. Don't think about your code in OOP terms, create a class structure from your schema. Use my example as a way to think differently about the problem, but don't just follow what I proposed blindly.
Summing up
If you want to stick with your original design, I think Table-Per-Hierarchy works best for you. But I strongly recommend re-thinking your schema and figuring out what kind of limitations apply to it, and whether you need to allow for those.

Entity Framework Navigation Property for a field that can store a foreign key from two different tables

I need a table called Loan.
The columns of this table will be:
Id, Type, BorrowId, Description
The trick here is that Type field will determine whether the borrower is an Employee or a Customer and then the BorrowerId will either be an Id from the Employee table or an Id from the Customer table.
Is this bad design as far as Entity Framework is concerned? The reason I ask is because it seems like I won't be able to create a Borrower Navigation property on the Loan table since the Id can be from two tables.
Does anyone have a solution for this? Like how I can change my data models to work with Navigation properties.
A simple answer to your question is "Yes it's a bad design". Referential Integrity should be strictly enforced and when you remove that ability by alternating the reference you create a window for errors. If you want two options create two columns, and create foreign keys on each to the tables they reference. Then your application will be effectively foolproof. :D

Code first, using a non-sequential Id

I have a code first project with a few tables, I am trying to determine that for a certain object the Id with which it will be inserted will not be the sequential Id that sql provides but an Id i will provide.
Although the code in my repository is creating the object properly and assigns it the wanted Id once it is inserted to my DB in the:
DbContext.Set<Containers>().Add(entity);
It is inserted as the next sequential Id.
In my code first the Id column for the base Entity from which all my entities derive is:
public int Id { get; set; }
I am looking the change to the Id's only in this entity.
Any suggestions?
this is the default behavior: when you don't alter it explicitly, EF will create an autoincrement column on the ID, if it's type is fitting.
To alter it, use Fluent API:
modelBuilder.Entity<Containers>().Property(x=>x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
or Data annotations:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
Maybe you'll have to run an migration after this to alter the table to non-autoincrement also. If you don't want to do that, you'll have to use Identity insert, wrapped in a transaction, every time you want this behavior.

Do unidirectional associations lead to non-required foreign key fields through NHibernate

Update
Added mappings below
Question summary
I have a database with many required foreign key fields and a code base with many unidirectional associations. I want to use NHibernate, but as far as I can tell, I either have to make the foreign key fields in the database NULLable (not a realistic option) or change the associations to bidirectional (not ideal either). Any other options that I've missed?
Backgrounds
I've joined a project that uses NHibernate to map tables 1:1 to so-called "technical" objects. After data retrieval, the objects are mapped to the actual domain model (AutoMapper style,implemented differently). I know that this is an unnecessary step and I want to propose removing it to the team. However, I'm running into an issue.
The domain model contains many unidirectional associations: the Case object has a list of Persons associated with the case, but the Persons do not hold a reference to the Case object. In the underlying database scheme, the Person table has a required foreign key field that references the case Id. The data model:
[ERD]
PERSON
CASE Id* Ids are generated by the DB
Id* <--FK-- CaseId* * denotes required fields
(other) (other)
The domain model looks like this:
public class Person : DomainEntity
{ // DomainEntity implements Id. Non-essential members left out }
public class Case : DomainEntity
{
public virtual IList<Person> Persons { get; set; }
}
Calling session.Save() on a Case leads to a database error (CaseId required when inserting into Person), because NHibernate starts with inserting the Person entries, followed by the Case entry and finishes by updating the CaseId column in the Person entries. If the CaseId column in the database is altered to non-required (allow NULLs), everything works as it should... however, that change is not an option at the moment (the database model is shared by several apps for at least another year).
The only way I have found to get NHibernate to execute the database actions correctly is by changing the association to bidirectional, i.e., by changing Person to
public class Person : DomainEntity
{
public virtual Case Case { get; set; }
}
This would involve significant changes to the existing codebase however, so I would prefer alternatives, if they exist. I've played around with component mappings, but that is a bad fit since most associations in our model are not actual (UML) compositions. Are there any other options that I've missed? TIA!
EDIT
The (Fluent) mapping for Case looks like this:
public class CaseMapping : ClassMap<Case>
{
public CaseMapping()
{
Not.LazyLoad();
Id(c => c.Id).GeneratedBy.Identity();
Map(x => x.Code).Not.Nullable().Length(20);
Map(x => x.Name).Not.Nullable().Length(100);
HasMany<Person>(x => x.Persons)
.AsBag()
.KeyColumn("CaseId")
.ForeignKeyConstraintName("FK_Person_Case")
.Cascade.AllDeleteOrphan();
}
}
If I use SessionSource.BuildSchema for a test database, this generates a Person table with a nullable CaseId column. I have not found a way for this to work with a non-nullable CaseId field without bidirectional associations. The executed (pseudo) SQL statements:
INSERT INTO Case...
select ##identity
INSERT INTO Person /* (all columns except CaseId) */
select ##identity
UPDATE Person SET CaseId = ? WHERE Id = ?;#p0 = 2, #p1 = 1
I think you may be out of luck here. The docs at http://nhibernate.info/doc/nh/en/index.html#collections-onetomany state:
If the column of a association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true"

Changing the order of LINQ to SQL Inserts

I have two LINQ to SQL classes, CandyBar and DeliciousCandyBar that map to tables of the same name in SQL Server.
There is a 0..1 relationship between CandyBar and DeliciousCandyBar. i.e, A CandyBar can have 0 or 1 DeliciousCandyBars. Conversely a DeliciousCandyBar has exactly one CandyBar.
In LINQ to SQL class, they look (basically) like
class CandyBar {
public int Id { get;set;} // this is primary key w/ autoincrement identity
public string Name {get;set;}
public EntityRef<DeliciousCandyBar> DeliciousCandyBar {get;set;}
}
class DeliciousCandyBar {
public int DeliciousnessFactor {get;set;}
public int CandyBarId {get;set;} // FK to candyBar Id
public EntityRef<CandyBar> CandyBar {get;set;} // the association property of the FK
}
To feed the database (via l2sql), my crawler goes out and finds candy bars and delicious candy bar.
But, with the first delicious candy bar my crawler inserts into the CandyStoreDataContext, the DataContext throws an exception when SubmitChanges is called.
The crawler runs the following code for one delicious candy bar. Please note this is an example. The exact process is more complex and I use a custom DSL crawler that spits out this object structure. Essentially, the following is performed.
var dc = CandyStoreDataContext();
var bar = new CandyBar() {
Name = "Flake",
DeliciousCandyBar = new DeliciousCandyBar() {
DeliciousnessFactory = 12
}
};
dc.CandyBars.InsertOnSubmit(bar);
dc.SubmitChanges();
On SubmitChanges(), a SqlException is thrown with the message "The INSERT statement conflicted with the FOREIGN KEY constraint FK_CandyBar_DeliciousCandyBar. The conflict occured in database CandyStoreData, table 'dbo.DeliciousCandyBar', column 'CandyBarId'".
The problem became clear when I dumped the CandyStoreDataContext.Log to Console.Out, the generated insert statements were round the wrong way. LINQ to SQL was trying to insert the DeliciousCandyBar first (which tried to set an invalid value in CandyBarId column), rather than inserting CandyBar first.
My question is, how do I get Linq to SQL to swap with the order of the insert statements?
I had assumed (incorrectly) that LINQ to SQL would know the direction of relationship dependency and do it the other way around.
UPDATE:
This post suggests I have the Association the wrong way around. But that doesn't make sense to me. It makes sense when modelled in the database. How could this be done the other way around.
On CandyBar, the association attribute on DelciousCandyBar property is
[Association(Name="DeliciousCandyBar_CandyBar", Storage="_DeliciousCandyBar", ThisKey="Id", OtherKey="CandyBarId", IsForeignKey=true)]
On DeliciousCandyBar, the association attribute on CandyBar property is
[Association(Name="DeliciousCandyBar_CandyBar", Storage="_CandyBar", ThisKey="CandyBarId", OtherKey="Id", IsUnique=true, IsForeignKey=false)]
Okay, now I'm confused, why is the second attribute marked as the foreign key.
I'm going to try recreating that relationship between CandyBar and DeliciousCandyBar in SQL Management studio
UPDATE 2
Okay, I tried creating the relationship both ways. And SSMS makes it really clear where the primary key is located (CandyBar.Id). I had it right the first time. Otherwise, the cascading would go backwards.
I would consider the possibility of it being a linq2sql bug with self referencing tables. Its a wild guess, but I recall linq2sql documentation saying somewhere it didn't support it that well. Perhaps there its the linq2sql designer that gets confused.
From the generated properties you posted, you can tell it has it backwards i.e. CandyBar has is pointing to delicious, instead of the other way around. Look at the generated code for other relations that work correctly.
Once you confirm it isn't working, and that by re-adding them in the designer doesn't sets them correctly, open the properties of a working association in the designer and make sure to have the association between candybar and deliciouscandy configured in the same way.
Please try this alternative:
Insert the instance of CandyBar without any child DeliciousCandyBar objects, then call the SubmitChanges() method.
Assuming you have an ID or GUID linking the two objects - lets say, CandyBarID. Then set the value of CandyBarID on the DeliciousCandyBar instance to that of the instance of CandyBar.
You could then insert the DeliciousCandyBar object, and because CandyBarID has been set, the relationship should be correct on selecting CandyBar objects.

Categories