I'm seeding data to SQL table through EF migration. Using OnModelCreating. Table I am seeding data in, has FK to other table. How do I configure that in OnModelCreating?
modelBuilder.Entity<UserEntity>().HasData(
new UserEntity
{
Id = Guid.NewGuid(),
CreatedAt = DateTime.Now,
CreatedBy = Guid.Empty,
Email = "[email protected]",
FirstName = "Jake",
LastName = "Carter"
}
);
These properties aren't FKs. There is one more property - PreferenceIndicatorId which is FK. How do I put that in OnModelCreating?
UPDATE : I tried creating PreferenceIndicator object and set the PrefenrenceIndicator in HasData() but after adding migration, Up() and Down() methods were empty.
modelBuilder.Entity<UserEntity>().HasData(
new UserEntity
{
Id = Guid.NewGuid(),
CreatedAt = DateTime.Now,
CreatedBy = Guid.Empty,
Email = "[email protected]",
FirstName = "Jake",
LastName = "Carter",
PreferenceIndicator = preferenceIndicator
}
);
CodePudding user response:
Does your PreferenceIndicator already exist?
Or are you creating a new one?
In general.
If your PreferenceIndicator (related object) does "pre-EXIST", then you can set the
UserEntity.PreferenceIndicatorId to this known value.
A good metaphor here would be an "Add Employee" functionality.
Most times, when you add a new Employee, your Employee.DepartmentKey will come from already created rows.
Thus you can set the Employee entity's DepartmentKey to an exact value.
Employee emp = new Employee();
emp.DepartmentKey = 333; /* 333 already exists in the database/dept-table */
....
If your relationship object does NOT "pre-exist".
This of course is the trickier situation.
Here you will NOT set the foreign-key SCALAR (UserEntity.PreferenceIndicatorId in your example or in my example the Employee.DepartmentKey). And this makes sense, you cannot set the FK SCALAR value because it does not exist yet.
You need to code the the NAVIGATION OBJECTS/PROPERTIES and allow EF to do the work for you.
BUT, you also need to setup the reciprocal values.
For example:
public class Department
{
public Department()
{
this.Employees = new List<Employee>();
}
public long DepartmentKey { get; set; }
public ICollection<Employee> Employees { get; set; }
and
public class Employee
{
public long EmployeeKey { get; set; }
public long MyParentDepartmentKey { get; set; } /* the scalar FK value */
public Department MyParentDepartment { get; set; } /* the full object */
..
Note, the Department has a 1:N relationship with Employees. (Whether it is 1:1, 1:N or M:N is not the primary concern here, but you need to code up the "reciprocal" side of things.
Again the below code is about the Department does not "pre-exist"
Department dept = new Department();
Employee emp1 = new Employee();
emp1.MyParentDepartment = dept;
// and now what is often overlooked, the RECIPROCAL relationship
dept.Employees.Add(emp1);
and now you can do something like
myDbContext.Departments.Add(dept);
myDbConext.SaveAsync(CancellationToken.None); << you should NOT use
.None here in your real code.
Remember, dept has a navigation property set for employee(S)...but also, your employee in that department has its MyParentDepartment set.
Note, navigation property OBJECTS were set, and none of the FK-SCALARS were set (because they are not known yet) (MyParentDepartmentKey as the main example here).
AFTER you call .SaveAsync, you should look at the objects in the myDbContext....and you should see hydrated Primary-Keys and the one FK.
In short, set navigation SCALARS when they pre-exist. set navigation object/properties (and RECIPROCATE these objects) when they do not pre-exist.
Note, my Department and Employee code ASSUMES that (and will not work unless) you have setup the property ORM mapping code already. it is not "magic fairy dust".
See:
https://www.learnentityframeworkcore.com/configuration/one-to-many-relationship-configuration
Personal tip:
You will learn EF better if you stop using ambiguous names for Type/PropertyName.
Instead of
public Employee
public Department Department {get; set;}
This is why I use
public Employee
public Department MyParentDepartment {get; set;}
or even
public Employee
public Department TheDepartment {get; set;}
or anything to disambiguate.
......
You can also see this "hydrate OBJECTS, not SCALARS" in the example at:
https://www.learnentityframeworkcore.com/dbcontext/adding-data
In the section labeled "Adding Multiple Records" (towards the end of the page)
The code:
var context = new SampleContext();
var author = new Author { FirstName = "Stephen", LastName = "King" };
var books = new List<Book> {
new Book { Title = "It", Author = author },
new Book { Title = "Carrie", Author = author },
new Book { Title = "Misery", Author = author }
};
context.AddRange(books);
context.SaveChanges();
No "primary key" or "foreign key" values are being set. BUT the Book.Author navigation property is being set by the lower case "author".
After .SaveChanges is executed..(and no exceptions of course)... if you look at the objects... you'll then see the PrimaryKey and ForeignKeySCALARS as being hydrated