Entity Framework - Mapping subclasses to existing tables with different keys - entity-framework

I have a legacy system that I am hoping to use EF to clean up the mess of ADO code it uses for data access.
The system uses the following class hierachy: Sponsors which are Members which are People. In the database, each class has it's own table, each with its own key.
Person
PersonId (PK)
Name
Member
MemberId (PK)
PersonId (FK)
Sponsor
SponsorId (PK)
MemberId (FK)
Mappings
Person
ToTable("Person");
HasKey(p => p.Id).Property(p => p.Id).HasColumnName("PersonId").IsRequired();
Member
ToTable("Member");
HasKey(m => m.MemberId).Property(m => m.MemberId).HasColumnName("MemberId").IsRequired();
Sponsor
ToTable("ChapterSponsor");
HasKey(cs => cs.MemberId).Property(cs => cs.MemberId).HasColumnName("MemberId").IsRequired();
I can map the Person and Member classes fine. But when I try to map the Sponsor class, I get an error because it is trying to find a field named PersonId on the Sponsor table.
Is it possible to tell EF that the Sponsor query needs to join using the MemberId Foreign Key? Or is this poor db structure not going to work with EF?

Related

Entity Framework - How to Insert to table with foreign keys without retrieving foreign table rows first

I'm having a hard time finding the exact answer to this question, so my apologies if this is redundant.
So I have 3 tables defined such that:
Person :PersonId, FirstName, LastName
Company: CompanyId, CompanyName
Order: OrderId, PersonId, CompanyId
On the Order table, there is a foreign key defined on the PersonId and CompanyId columns, thus, my Order entity class generated by EF has a navigation properties of type Person (not PersonId) and Company.
So, to insert into the Order table, I first need to query the person and company tables to get the person and company entities. Then I can construct the Order object using the Person and Company entities and save it to the db.
In my scenario, I am being passed a PersonId and CompanyId.
In classic SQL I would just do INSERT INTO Order Set (CompanyId, PersonId) - 1 database call. But with EF, I have to do 3 db calls. This seems like overkill.
Is there any way around this?
PS - I'm using EF 6. I know I could generate an expression and make it single call..but that would still yield two subselects.
You can just include foreign key properties in addition to the navigation properties and then set them using the ids you have. If you do this will not have to go to the database to get related entities for just a sake of setting the relationship.

Association with Different Column Names in Entity Framework

I have a table Person with a Primary Key of PersonId. I have another table CheckDetails with a column named DirectorId. There is a Foreign Key between Person.PersonId and CheckDetails.DirectorId. It is a 1-to-Many relationship
I created 3 entities: Person, Director, and CheckDetail.
Person maps back to the Person table and has PersonId as its key.
Director inherits from Person and has an ICollection of CheckDetail.
CheckDetail has Director property named Director.
I used the following when mapping Director:
HasRequired( d => d.CheckDetails ).WithMany( ).HasForeignKey( d => d.PersonId );
but I get the following error: The foreign key component 'PersonId' is not a declared property on type 'Director'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.
How do I create this association?

Entity Framework table per type inheritance with PK->FK, not PK->PK

I have to create an entity framework model for a badly designed database. The database uses table per type inheritance but it does so with using a PK->FK relationship, not a PK->PK relationship. E.g.
Person
PersonID (PK)
Name
Employee
EmployeeID (PK)
PersonID (FK)
DateStarted
HourlyEmployee
HourlyEmployeeID (PK)
EmployeeID (FK)
HourlyRate
Obviously this is just badly designed, but I can't change it. Table per type inheritance in the entity framework essentially wants EmployeeID not to exist and the PK for Employee to be PersonID. Is it possible to create a model for this database, or do I choose another tool? any recommendations?
You will not map this as TPT inheritance because your database is configured in the way that doesn't allow you cheating EF.
If Employee.EmployeeID is auto-generated in the database and Employee.PersonID is unique (uniqueness must be enforced in the database) you should be able (not tested) to cheat EF by simply mapping:
public Employee : Person {
public DateTime DateStarted { get; set; }
}
This class will tell EF that Employee inherits key from Person (PersonID) and you will hide the real key from EF - this should work if the real key is auto-generated.
The problem is your next level of inheritance which breaks this pattern. To make this work your HourlyEmployee will have to reference PersonID - not EmployeeID. EF now doesn't know about EmployeeID existence so it even cannot map relation with HourlyEmployee.
TPT inheritance in code first has one additional limitation - PK column must have the same name in all tables.
You can create a model from the database if it exists but it might not be what you expect. EF sometimes doesn't work that great with weird database structures.

entity frame work does not support one-to-one containment

If a user has multiple locations
And if a user has a single role.
My table design will be like
TableUser
Userid (pk)
Username
RoleId (fk)
TableRole
RoleId (pk)
RoleName
TableLocation
LocationId (pk)
LocationName
UserLocation
LocationId (fk) (part of composite pk)
Userid (fk)(part of composite pk)
I have entity framework 4.0.
When I fetch a user entity the user entity does not have a Role object with it.
But it does have a Location object.
Why is this like this?
Is it the default behavior of entity framework?
Does it support only one-to-many relations by default?
Yes, EF doesn't support one-to-one relation modeled this way. To enforce this relation in the database you must mark RoleId in the database with unique index / constraint. EF doesn't support unique keys so it cannot model this relation as one-to-one. The only way to model one-to-one relation in EF is on top of primary keys:
Role - PK RoleId
User - PK, FK UserId
That means that instead of User.RoleId you will use User.UserId as FK to Role.
If you want to keep your current structure you must make it one-to-many relation (one role can have many users), don't expose Users navigation property on the Role and place unique key to the database. It will still allow you assigning multiple users to single role in the application but database will fire exception if you try to save it.

How to do many-to-many relation between the same entity

I have an Employee entity class with (Id,Name,EmployeeType). EmployeeType entity (Id, Description) where Description can be either REGULAR/MANAGER.
I am confused on how to map Employees who are of type REGULAR to their corresponding MANAGER type Employees. Should I just add an extra field to the Employee entity itself so that it now becomes (Id, Name, EmployeeType, ManagerEmployeeId)? Or should I instead have a lookup table Employee_Manager (Id, RegularEmployeeId, ManagerEmployeeId)?
I am considering going with the Employee_Manager lookup table and am not sure how that entity class would look like. The following below is what comes to my mind. Am I on the right track here?
#Entity
#Table(name="EMPLOYEE")
public class Employee{
#Id
int id;
#Column(name="NAME")
String name;
#ManyToMany(mappedBy = "regularEmployee")
Collection<Employee> regularEmployee
#ManyToMany
Collection<Employee> managerEmployee;
}
ps. I am using JPA with Hibernate as the persistence provider.
If you're trying to have an employee have exactly one manager, then first of all you're doing a many-to-one relation (not many-to-many) and having the ManagerEmployeeID in the table as a foreign key reference to the same table is just fine.
Use a lookup table if you want to allow an employee to potentially have more than one managerial-type role. You can also use this if you want to assign a particular "role" to these manager-type people:
create table Supervisors (
eid int,
sid int,
role varchar(16)
);
Then you could use role for "Supervisor" vs "Manager" vs "Slavedriver" vs who knows what.
Sorry, I don't know any JPA/Hibernate, so the concepts (and pseudo-SQL) is the best I can give you.
Hope that helps a bit.