简体   繁体   中英

How to reload entity in EntityFramework?

I hava a classes:

public class abstract Person{
    public int Id{set;get;}
    public string Name {set;get;}
}

public class Student:Person{
    public string Specialisation {set;get;}
}

public class Instructor:Person{
   public decimal Salary {set;get;}
}

In database i have tables: Persons, Students, Instructors for this classes.

Now in my application i want to change one of students to instrector. I mean that i need to change entity type BUT i need to save same Id . I did not found how to do this with EF so i just use SQL script:

using (var command = db.Database.Connection.CreateCommand())
            {
                if (command.Connection.State == ConnectionState.Closed) command.Connection.Open();

                if (db.Database.CurrentTransaction != null)
                    command.Transaction = db.Database.CurrentTransaction.UnderlyingTransaction;

                command.CommandText = $@"delete from [dbo].[Students] where Id = @id;
                                        insert into [dbo].[Instructors](Id) values(@id)";

                command.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Value = myId });
                command.ExecuteNonQuery();
            }

But when i tried to got this new Instructor in same context i got error:

   var instructor = db.Instructors.FirstOrDefault(t=>t.Id = myId);

   All objects in the EntitySet 'myContext.Person' must have unique primary keys. However, an instance of type 'Person.Instructor' and an instance of type 'Person.Student' both have the same primary key value, 'EntitySet=Person;Id=1'. 

I tried to reload base entity:

var myPerson = db.Persons.FirstOrDefault(t=>t.Id = myId);

///
my sql where i delete Student and insert Instructor
///

db.Entry(myPerson).Reload();

var instructor = db.Instructors.FirstOrDefault(t=>t.Id = myId);

But got same error. So how to make this correctly?
I mean maybe my solution completly wrong? Or if not that how can i reload entity?

A meme of Sean Bean's Boromir stating "One does not simply change an entity's type" would be appropriate. When it comes to inheritance at a simple level, a Dog and a Cat can inherit from Animal, but a Dog never becomes a Cat.

A Person is a entity. What they do is a Role, not an entity, or if it is an entity, it can be associated to that person.

For instance, using Person, Instructor, Student, Course:

A Course has an instructor and students. If Students and Instructors extend Person then a Student's PK is a PersonId, and an instructor's PK is PersonID. My table structure might look something like:

Person [PersonId, Name, ... common fields]

Instructor [PersonId, ... instructor fields]

Student [PersonId, ... student fields]

Course [CourseId, InstructorPersonId, Name, ... course fields]

CourseStudent [CourseId, StudentPersonId]

Or alternatively, Person/Student/Instructor schema could be:

Person [PersonId, Role, Name, ...]

Where Role is a discriminator that EF can use to differentiate between an Instructor and Student inheritance. Either way, it's not inherently a good model because what ensures that a course's instructor is actually pointing at a Person associated to an Instructor row? If you were to merely delete an instructor row for a person to make them a student, a course could still consider them as the instructor.

Instead, you should consider association. People don't change, merely their roles change. Every course needs an instructor and it will have students and there will likely be details that are specific to that instructor (qualifications) and students. (grades)

Person [PersonId, Name, ...]

Role [RoleId, Name] // Ie "Instructor"

PersonRole [PersonId, RoleId]

Instructor [InstructorId, PersonId, ...] // Think of as an "Instructor Position"

Student [StudentId, PersonId...] // Can be thought of as a "Student Spot"

Course [CourseId, InstructorId, Name, ...]

StudentCourse [StudentId, CourseId]

In this case, Instructor and Student don't inherit from Person, they are associated to a person. A person can hold associations to roles which can be considered when a person could be associated to an Instructor position or not. The application will still need to regulate rules around associations such as if an instructor position gets filled by another person, and ensuring that a course doesn't have the same "person" serving as an instructor and a student and that student spots don't switch people. (grades don't transfer)

In this way you can create/manage instructors and students independently of the people behind them. "Student" as an entity is entirely optional, instead the CourseStudent could just associate PersonId, and stuff like grades can be associated directly to Person. The fact that a person that was a student and had grades for instance earns a role of Instructor and can be associated to an Instructor position for a course doesn't break anything.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM