I have the following model (scaled down of course)
public class WorkOrder
{
public int ID {get; set;}
public virtual ICollection<WorkOrder_Worker> Workers {get; set;}
}
public class WorkOrder_Worker
{
public int ID {get; set;}
[ForeignKey("Worker")]
public int WorkerID { get; set; }
public virtual AdminProfile Worker { get; set; }
public virtual WorkOrder WorkOrder { get; set; }
}
I have code such as the following:
Context.WorkOrders.Where(a=>a.ID == 1).Workers.RemoveAll();
Context.SaveChanges();
In the database, this is only setting the field "WorkOrder_ID" = NULL instead of deleting the row in the database. How do I delete the entire row?
Related
I have been using the .Net 5 and EF Core 5 for a small web app. Given EF Core 5 supports many - many out of the box there is no need for a joining table.
I've run into an issue when updating a object that already exists in the DB. For my app I have Athletes and Parents which have the many - many relationship.
public class Athlete
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Email { get; set; }
public string ContactNumber { get; set; }
public string Street { get; set; }
public int Postcode { get; set; }
public string City { get; set; }
public StateEnum State { get; set; }
public DateTime DateofBirth { get; set; }
public DateTime DateSignedUp {get; set;}
public virtual ICollection<Parent> Parents { get; set; }
}
public class Parent
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Email { get; set; }
public string ContactNumber { get; set; }
public string Street { get; set; }
public int Postcode { get; set; }
public string City { get; set; }
public StateEnum State { get; set; }
public DateTime DateofBirth { get; set; }
public DateTime DateSignedUp {get; set;}
public virtual ICollection<Athlete> Athletes { get; set; }
}
When I try to update the existing athlete that has a relation ship with two other parents I get an error:
Violation of PRIMARY KEY constraint 'PK_AthleteParent'. Cannot insert
duplicate key in object 'dbo.AthleteParent'. The duplicate key value
is (31, 1)
[HttpPost]
public async Task<ActionResult<Athlete>> PostAthlete(Athlete athlete)
{
_context.Athletes.Update(athlete);
await _context.SaveChangesAsync();
return Ok(athlete));
}
From what I can tell when entity tries to update my Athlete it tries to insert new rows into the joining table even though the parents already exist in there. Is there a way to get entity to remove any records when the relationship is updated? Or is there a way to tell entity to take update the joining table to match the Athlete object that is passed in?
Given a simple example like this:
public class Foo {
Guid Id { get; set; }
ICollection<Bar> Bars { get; set; }
}
public class Bar {
Guid Id { get; set; }
ICollection<Foo> Foos { get; set; }
}
You can call clear() on a tracked instance of Foo, and then re-add the Bar instances that you want assigned. I've found this is a nice way to avoid the constraint exception - much easier than manually trying to figure out what Bars have changed.
var foo = context.Foos.Include(x => x.Bars).FirstOrDefault(x => x.Id == someGuid);
foo.Bars.Clear();
foo.Bars.Add(bar1);
foo.Bars.Add(bar2);
...
context.Update(foo);
context.SaveChanges();
I've a problem in customize view in my application that upload images
i have three models
public int EmpId { get; set; }
public string EmployeeName { get; set; }
public virtual ICollection<Picture> picture{ get; set; }
and second
public int MacId { get; set; }
public string machine { get; set; }
and third
public int PicId { get; set; }
public string PicPath { get; set; }
public int MacId { get; set; }
public int EmpId { get; set; }
public virtual Employee Employee { get; set; }
and i want to make it show picture of mac and who is the employee who take it ?
Create New Model With the neccesary properties you want to bind to your view.
for eg:
class newModelName
{
public Model1TypeName model1 {get ; set; }
public Model2TypeName model2 {get ; set; }
public Model3TypeName model3 {get ; set; }
}
Now you can bind this new model to your view which will have all necessary information from all the three views.
I have two classes
public class Project
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int ManagerID { get; set; }
public int CoordID { get; set; }
[ForeignKey("ManagerID")]
public virtual Employee Manager { get; set; }
[ForeignKey("CoordID")]
public virtual Employee Coord { get; set; }
}
public class Employee
{
[Key]
public int EmpID { get; set; }
public string Name { get; set; }
[InverseProperty("ManagerID")]
public virtual ICollection<Project> ManagerProjects { get; set; }
[InverseProperty("CoordID")]
public virtual ICollection<Project> CoordProjects { get; set; }
}
The ManagerID and CoordID map to the EmpID column of the Employee table.
I keep getting an error for Invalid Columns becauce EF is not able to map correctly. I think it is looking for wrong column.
I think InverseProperty is used to refer to the related navigation property, not the foreign key, e.g.
public class Employee
{
[Key]
public int EmpID { get; set; }
public int Name { get; set; }
[InverseProperty("Manager")]
public virtual ICollection<Project> ManagerProjects { get; set; }
[InverseProperty("Coord")]
public virtual ICollection<Project> CoordProjects { get; set; }
}
Also, is there a reason why your names are ints and not strings?
Best guess would be to use fluent API in your context via OnModelCreating. By renaming the column, EF can't figure out the original object to map so it's confused. However, Fluent API allows you to manually specify the map using something like the following:
public class MyContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Project> Projects { get; set; }
protected override OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>()
.HasRequired(x => x.Manager)
.WithMany(x => x.ManagerProjects)
.HasForeignKey(x => x.ManagerID);
modelBuilder.Entity<Project>()
.HasRequired(x => x.Coord)
.WithMany(x => x.CoordProjects)
.HasForeignKey(x => x.CoordID);
}
}
I'm having trouble wrapping my head around a certain code-first relationship. I have three entities: Group, User, GroupPermission. The GroupPermission entity holds information about permissions that relate to a group. There are three permissions: leader, editor, user. The GroupPermission table should include the primary key Id and the name of the permission. Then I want a relationship table that looks something like this: Id - Group_Id - User_Username - GroupPermission_Id. There can be multiple groups, multiple users, multiple permissions. I have plenty of examples that help me make a single relationship table, but I can't find anything that includes multiple relationships.
Here are my entities...
User:
public class User
{
[Key, StringLength(EntityLength.UsernameLength)]
public string Username { get; set; }
[Required, StringLength(EntityLength.NameLength)]
public string FirstName { get; set; }
[Required, StringLength(EntityLength.NameLength)]
public string LastName { get; set; }
[Required, StringLength(EntityLength.Email)]
public string Email { get; set; }
public bool Active { get; set; }
public DateTime DateCreated { get; set; }
public virtual UserPermission UserPermission { get; set; }
public virtual ICollection<Group> Groups { get; set; }
public virtual ICollection<Project> Projects { get; set; }
public virtual ICollection<Issue> Issues { get; set; }
public virtual ICollection<GroupPermission> GroupPermissions { get; set; }
public string FullName
{
get { return FirstName + ' ' + LastName; }
}
}
Group:
public class Group
{
[Key]
public int Id { get; set; }
[Required, StringLength(EntityLength.GenericLength)]
public string Name { get; set; }
[Required, StringLength(EntityLength.DescriptionLength)]
public string Description { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Project> Projects { get; set; }
public virtual ICollection<GroupPermission> GroupPermissions { get; set; }
}
GroupPermission:
public class GroupPermission
{
[Key]
public int Id { get; set; }
[StringLength(EntityLength.GenericLength)]
public string Name { get; set; }
public int GroupId { get; set; }
public virtual ICollection<Group> Groups { get; set; }
public int UserId { get; set; }
public virtual ICollection<User> Users { get; set; }
public enum Permission
{
Leader = 1,
Editor = 2,
User = 3
}
}
When the tables are created using this structure, I get a GroupPermissions table that has Id, Name, GroupId, and UserId. This table needs to only be Id and Name. Then it creates a GroupPermissionUsers table that holds GroupPermissions_Id and User_Username. This is the table that should be Id, Group_Id, User_Username, GroupPermission_Id.
Does anybody have any tips to accomplish this or am I thinking about the design of this incorrectly?
In such case you are missing additional entity. It should look like:
New Permission entity with Id and Name:
public class Permission
{
[Key]
public int Id { get; set; }
[StringLength(EntityLength.GenericLength)]
public string Name { get; set; }
public virtual ICollection<GroupPermission> GroupPermissions { get; set; }
}
Modified GroupPermission entity to form junction table among Users, Groups and Permissions:
public class GroupPermission
{
[Key]
public int Id { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
public string UserName { get; set; }
[ForeignKey("UserName")]
public virtual User User { get; set; }
public int PermissionId { get; set; }
public virtual Permission Permission { get; set; }
}
I'd like to change the default behavior of .Where method for specific case(s).
All my Business Objects inherit from BaseObject that has property int ID {get; set;}
// Base class
public abstract class BaseObject
{
public abstract int ID {get; set;}
}
I have 2 classes:
public partial class User : BaseObject
{
public override int ID {get; set;}
public string Username { get; set; }
public int ProfileID { get; set; }
public virtual Profile Profile { get; set; }
}
public partial class Profile : BaseObject
{
public override int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
public static Profile GetAdminProfile()
{
return new Profile(){ID = 3, Name = "Admin profile"};
}
}
I would like to write
// This throws Unable to create a constant value of type 'Profile'... exception
User admin = Users.Where(user.Profile == Profile.GetAdminProfile()).FirstOrDefault();
instead of
User admin = Users.Where(user.Profile.ID == Profile.GetAdminProfile().ID).FirstOrDefault();
Is there a way to achieve this?
This is a known problem in Entity Framework. You will have follow the second approach.