Adding Entity with complex type property - entity-framework-core

I am trying to add the student entity in my database, which looks like this:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public Course Course { get; set; }
}
The Course class looks like this:
public class Course
{
public int ID { get; set; }
public string Name { get; set; }
}
Data in the Course table:
| ID | Course |
------------------------
| 1 | Math |
-----------------------
| 2 | Physics |
-----------------------
When I define student as shown below:
var student = new Student
{
Name = "ABC",
Course = new Course { ID = 1, Name = "Math"}
};
and try to add it so
context.Students.add(student);
await context.SaveChangesAsync()
the entity wasn't added. I added this line of code
context.Entry(student).State = EntityState.Added;
but nothing changed.

First of all you have to set Foreign Key CourseId to your Student entity.
A) Student Entity
public class Student
{
public int StudentID { get; set; }
public string Name { get; set; }
public int CourseID { get; set; } //This is foreign key
public virtual Course Course { get; set; }
}
B) Course Entity: ICollection property gives you all students with particular CourseID.
public class Course
{
public int CourseID { get; set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
1) If you add new student record with new course then
Course course = new Course
{
Name = "Math"
};
Course insertedCourse = context.Courses.Add(course);
Student student = new Student
{
CourseID = insertedCourse.CourseID,
Name = "ABC"
};
context.Students.Add(student);
await context.SaveChangesAsync();
2) If you have to reference your existing course from database then you have to get course from database and assign courseId to student entity.
Course existingCourse = GetCourseByIdFromDatabase();
Student student = new Student
{
CourseID = existingCourse.CourseID, //This ID comes from Db
Name = "ABC"
};
context.Students.Add(student);
await context.SaveChangesAsync();
Try once may it help you.
Edited:
As I understood with your last comment,
If you want to get student with its corresponding course then
Your get student method look like
public Student GetStudent(int Id)
{
Student student = context.Students.Find(Id);
return new Student
{
StudentID = student.StudentID,
Name = student.Name,
Course = student.Course
};
}
Ad you can access student's course like
Student student = GetStudent(1);
string CourseName = student.Course.Name;
you can use your async and await with above code depending your need.

Related

asp.net web api server data not syncing with database between BL

Hello I am new to servers and REST API and am trying to extract data from a dynamically created table and the data does not sync with the data in the database.
I have an sql database from which I extracted an entity database in asp.net web project.
This is an example for GET of one entity class (exists in database):
public class EmployeeBL
{
private FSProject1Entities db = new FSProject1Entities();
public List<Employee> GetEmployees(string fname, string lname, string depID)
{
return GetEmployeeSearchResult(fname, lname, depID);
}
}
And this is an example for a method from a class such as I created in order to combine data from 2 tables:
public class ShiftEmployeeDataBL
{
private FSProject1Entities db = new FSProject1Entities();
private List<ShiftEmployeeDataBL> GetEmployeeByShiftID(int id)
{
List<ShiftEmployeeDataBL> shiftEmpData = new List<ShiftEmployeeDataBL>();
foreach (Employee emp in db.Employee)
{//build list... }
return shiftEmpData;
}
My problem is that db.Employee via this GET request path (ShiftEmployeeData) is old data and via Employee GET request is good data (assuming the data was updated via Employee path).
And vice versa - it would appear that if I update Employee via ShiftEmployeeData class, it would appear as good data for ShiftEmployeeData class and not update for Employee.
I have APIcontrollers for both classes.
what is happening? I feel like I am missing something.
I tried closing cache options in browser.
update with code for elaboration:
entity Employee:
public partial class Employee
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int StartWorkYear { get; set; }
public int DepartmentID { get; set; }
}
employee update(auto generated by entity model code generation from db):
public void UpdateEmployee(int id, Employee employee)
{
Employee emp= db.Employee.Where(x => x.ID == id).First();
emp.FirstName = employee.FirstName;
emp.LastName = employee.LastName;
emp.StartWorkYear = employee.StartWorkYear;
emp.DepartmentID = employee.DepartmentID;
db.SaveChanges();
}
employeeshiftdata class (not a db table but still in the models folder):
public class EmployeeShiftData
{
public int ID { get; set; } //EmployeeID
public string FirstName { get; set; }
public string LastName { get; set; }
public int StartWorkYear { get; set; }
public string DepartmentName { get; set; }
public List<Shift> Shifts { get; set; }
}
employeeshift GET part of the controller:
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class EmployeeShiftDataController : ApiController
{
private static EmployeeShiftDataBL empShiftDataBL = new EmployeeShiftDataBL();
// GET: api/EmployeeShiftData
public IEnumerable<EmployeeShiftData> Get(string FirstName = "", string LastName = "", string Department = "")
{
return empShiftDataBL.GetAllEmployeeShiftData(FirstName, LastName, Department);
}
//...
}
Would need to see the code that interacts with the database, especially the code that makes the updates.
If the changes are written with Entity Framework, are the models themselves properly related with navigational properties?
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public List<EmployeeShift> EmployeeShifts { get; set; }
// etc.
}
public class EmployeeShift
{
public int Id { get; set; }
public Int EmployeeID { get; set; }
public Employee Employee { get; set; }
// etc.
}
If those are good, and both models are covered by Entity Framework's context tracking, then both should be updated.

Reliable Service Data Model Issue

I'm new to Azure Service Fabric, and watched Ivan Gavryliuk's "Understanding the Programming Models of Azure Service Fabric" course on Pluralsight. I've been following along and the basic data model in the reliable service and API work as explained in the course.
However, if I increase the complexity of the data model used I hit an error.
Product.cs from the ECommerce.ProductCatelog.Model
namespace ECommerce.ProductCatalog.Model
{
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int Availability { get; set; }
public Supplier Suppliers { get; set; }
}
public class Supplier
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}
ApiProduct.cs from ECommerce.API.Model
public class ApiProduct
{
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("price")]
public double Price { get; set; }
[JsonProperty("isAvailable")]
public bool IsAvailable { get; set; }
[JsonProperty("suppliers")]
public ApiSupplier suppliers { get; set; }
}
public class ApiSupplier
{
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
ProductController.cs from Ecommerce.API.Controlers
[HttpGet]
public async Task<IEnumerable<ApiProduct>> GetAsync()
{
IEnumerable<Product> allProducts = await _service.GetAllProductsAsync();
return allProducts.Select(p => new ApiProduct
{
Id = p.Id,
Name = p.Name,
Description = p.Description,
Price = p.Price,
IsAvailable = p.Availability > 0,
suppliers = p.Suppliers
});
}
The last line in the above block triggers an intellisense error:
"Cannot implicitly convert type 'ECommerce.ProductCatelog.Model.Supplier' to 'ECommerce.API.Model.Supplier'"
Any suggestions on how to work around this welcome :)
Cheers,
Adam
Your problem is not specific to Service Fabric but C# in general. You are trying to set a variable with a value of a different type.
In this line:
IEnumerable<Product> allProducts = await _service.GetAllProductsAsync();
You get a collection of items of type ECommerce.ProductCatalog.Model.Product. In this class, you added the property Suppliers (which should be Supplier since it's not a collection) of type ECommerce.ProductCatalog.Model.Supplier.
Now, with the following line:
return allProducts.Select(p => new ApiProduct
{
Id = p.Id,
Name = p.Name,
Description = p.Description,
Price = p.Price,
IsAvailable = p.Availability > 0,
suppliers = p.Suppliers
});
you are converting this collection to a collection of a new type ECommerce.API.Model.Product, to which you added a new property Suppliers of type ECommerce.API.Model.Supplier, but you set this property to the original value, without converting it. So, convert the original Suppliers property to the correct type:
return allProducts.Select(p => new ApiProduct
{
Id = p.Id,
Name = p.Name,
Description = p.Description,
Price = p.Price,
IsAvailable = p.Availability > 0,
suppliers = new ApiSupplier
{
Id = p.Suppliers.Id,
Name = p.Suppliers.Name
}
});
Update: make Suppliers a collection
Make your Suppliers property a collection both in your data model and in your Api model:
public Collection<ApiSupplier> suppliers { get; set; }
Then convert the collection accordingly:
return allProducts.Select(p => new ApiProduct
{
Id = p.Id,
Name = p.Name,
Description = p.Description,
Price = p.Price,
IsAvailable = p.Availability > 0,
suppliers = p.Suppliers.Select(s => new ApiSupplier
{
Id = s.Id,
Name = s.Name
}
});

How to Allow NULL Foreign Keys with SQLite-net-extensions

I'm trying to add a nullable foreign key mapping but it doesn't work. I know the database allows nulls, since I can insert a new record with a null foreign key when using Datagrip. I only get the error when trying to insert from a Xamarin.Forms project building for Android(SQLite.SQLiteException: 'Constraint')
My classes look like:
public class Item
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
...
[ForeignKey(typeof(Location))]
public int LocationId { get; set; }
[ManyToOne]
public Location Location { get; set; }
}
public class Location
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
...
[OneToMany]
public List<Item> Items { get; set; }
}
And my inserts like
//This will no work
var todoItem = new Item()
{
Name = "Test item " + DateTime.Now.TimeOfDay.ToString(),
Description = "Desc",
Location = null // I tried with and without this line
};
await App.Database.SaveItemAsync(todoItem);
//This will work
var todoItem = new Item()
{
Name = "Test item " + DateTime.Now.TimeOfDay.ToString(),
Description = "Desc",
LocationId = 1
};
await App.Database.SaveItemAsync(todoItem);
Any idea what I'm doing wrong? Thanks
Apparently the library needs that the id field to be nullable, so instead of
[ForeignKey(typeof(Location))]
public int LocationId { get; set; }
I should use
[ForeignKey(typeof(Location))]
public int? LocationId { get; set; }
PS: In my case just building the project didn't took the changes on to effect, I only could see the result after Rebuild the project..(I'm new with Xamarin, probably I have something misconfigured...I hope)

EF Core - Cannot add object with composite key

Alright, I'm trying to make a Wishlist containing user favorite items, however when I try to add them to the user, EF doesn't even try to INSERT, no action.
Here is my FavoriteProduct model
public class FavoriteProduct : BaseDeletableModel<int>
{
public string FashionNovaUserId { get; set; }
public FashionNovaUser FashionNovaUser { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
builder.Entity<FavoriteProduct>().HasKey(x => new { x.ProductId, x.FashionNovaUserId });
Here's my user model
public class FashionNovaUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<FavoriteProduct> FavoriteProducts { get; set; }
Then through my service layer I'm trying to add the favoriteProduct to user's list
var favoriteProduct = new FavoriteProduct
{
ProductId = id,
FashionNovaUserId = user.Id
};
user.FavoriteProducts.Add(favoriteProduct);
this.db.SaveChanges();
When I do that, there database table is not updated, nor it has any new entries.
Since FashionNovaUser and Product are many-to-many relationships, if you would like to add records of FavoriteProduct in join table, just use
var favoriteProduct = new FavoriteProduct
{
ProductId = id,
FashionNovaUserId = user.Id
};
this.db.Add(favoriteProduct);//or this.db.FavoriteProduct.Add(favoriteProduct)
this.db.SaveChanges();

Many to Many relationships with look up tables

public class Person {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[ManyToMany(typeof(PersonColor), CascadeOperations = CascadeOperation.All)]
public List<Color> FavoriteColors { get; set; }
}
public class Color {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[ManyToMany(typeof(PersonColor))]
public List<Person> People { get; set; }
}
public class PersonColor {
[ForeignKey(typeof(Person))]
public int PersonId { get; set; }
[ForeignKey(typeof(Color))]
public int ColorId { get; set; }
}
...
var person = new Person() {
FirstName = "Adrian",
LastName = "Simbulan",
FavoriteColors = new List<Color>() {
new Color() {Name = "Red"},
new Color() {Name = "Green"}
}
};
await _db.InsertWithChildrenAsync(person);
Ok so i'm trying to establish a many to many relationship between Person and Color. The color table will be pre-populated with static data.
Now the problem is, whenever I execute the "InsertWithChildrenAsync" command, it always inserts new data into the Color lookup table. Is there a way to insert a Person record with selected colors with out affecting the Color table?
Try removing the write cascade operation from FavoriteColors attribute:
[ManyToMany(typeof(PersonColor), CascadeOperations = CascadeOperation.CascadeRead)]
public List<Color> FavoriteColors { get; set; }
This way the library won't perform recursive write operations on that table.
Another way without modifying the relationship is performing a two-step operation. First inserting the object and then updating the relationship:
await _db.InsertAsync(person);
await _db.UpdateWithChildrenAsync(person);
In both cases the the objects in the FavoriteColors list should already exist in the database and should have a valid primary key assigned. According to this, your sample code will never work because the identifier is 0 in all Color objects.