How do I build a class that shares a table with multiple columns in MVC3? - asp.net

I have a Job table
public class Job
{
public int JobId { get; set; }
public int SalesManagerId { get; set; }
public int SalesRepId { get; set; }
}
and a Person table
public class Person
{
public int PersonId { get; set; }
public int FirstName { get; set; }
public int LastName { get; set; }
}
My question is, how do I link the SalesManagerId to the Person (or PersonId) as well as the SalesRepId to the Person (PersonId)? The Sales Manager and Sales Rep are independent of each other. I just don't want to make 2 different lists to support the Sales Manager and Sales Rep roles.
I'm new to MVC3, but it seems public virtual Person Person {get; set; } would be the way to go, but that doesn't work.
Any help would be appreciated!
Thanks!

Change your Job class like this
public class Job
{
public int JobId { get; set; }
public virtual Person SalesManager { set; get; }
public virtual Person SalesRep { set; get; }
}
This will create the Job table with 3 columns. JobId, SalesManager_PersonID (ForiegnKey) ,SalesRep_PersonID (Foriegn key)

Related

EF Core Referencing same table, single collection

Let's startof with the result I would like to have.
I have a member which can have multiple dance partners.
Each dance couple is bound to a course.
So the situation of the models are:
Member:
Id
...
Course:
Id
...
MemberPair:
Id
CourseId
Member1Id
Member2Id
Entityframework core gives me the following solution:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid Member1Id { get; set; }
[Required]
public Guid Member2Id { get; set; }
[Required]
public Guid CourseId { get; set; }
public virtual Member Member1 { get; set; }
public virtual Member Member2 { get; set; }
public virtual Course Course { get; set; }
}
and
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
...
public virtual List<MemberPair> MemberPairs1 { get; set; }
public virtual List<MemberPair> MemberPairs2 { get; set; }
}
But my ideal solution is:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid PartnerId { get; set; }
[Required]
public Guid CourseId { get; set; }
public virtual Member Partner{ get; set; }
public virtual Course Course { get; set; }
}
and
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
...
public virtual List<MemberPair> Partners { get; set; }
}
I know that the ideal solution is not valid. But is there another solution that is better?
When I iterate all members I have to find out if I have to use MemberPairs1 or MemberPairs2 , and I would like to know if this can be made easier.
Thanks in advance.
Your comment triggered me to search for other solutions. So despite the fact that you've already accepted the answer, I wanted to explore some alternatives.
The problem with partner is that this is relative to the member. From member1's perspective member2 is the partner and vice versa.
The only way to implement this, more or less out-of-the-box, is to add redundant data. And by that I mean add the data from both perspectives.
For that we need to include Member in MemberPair:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid MemberId { get; set; }
[Required]
public Guid PartnerId { get; set; }
[Required]
public Guid CourseId { get; set; }
public Member Member { get; set; }
public Member Partner { get; set; }
public Course Course { get; set; }
}
Suppose you have:
Pair1 = { Id = 1, MemberId = 1, PartnerId = 2, CourseId = 1 }
Pair1Swap = { Id = 2, MemberId = 2, PartnerId = 1, CourseId = 1 }
Pair2 = { Id = 3, MemberId = 1, PartnerId = 3, CourseId = 2 }
Pair2Swap = { Id = 4, MemberId = 3, PartnerId = 1, CourseId = 2 }
Where ~swap is the redundant data. In that case
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
// As the data is redundant only look at memberId. Check the fluent code.
// MemberPairs should contain a list of pairs where 'this' is a member.
// When (Member)Id == 1 then Pair1 + Pair2
// When (Member)Id == 2 then Pair1Swap
public ICollection<MemberPair> MemberPairs { get; set; }
}
You can then query:
member.MemberPairs.Select(p => p.Partner);
// result for Id==1: Partner with Id 2 and Partner with Id 3.
// result for Id==2: Partner with Id 1.
The drawback is that you'll have redundant data, which needs to be managed! But given this is just a team of two, I think this is quite easy to implement and an acceptable solution.
An alternative is to extend the Member object with an additional property (or method if you like), that generates a list of partners. In that case you don't need redundant data, nor an additional table. But you'll have to populate both memberPair collections.
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public List<MemberPair> MemberPairs1 { get; set; }
public List<MemberPair> MemberPairs2 { get; set; }
public ICollection<Member> Partners
{
get
{
// Get all pairs where 'this' is a member.
var pairs = MemberPairs1.Union(MemberPairs2);
// Get all partners by filtering by Id.
return pairs.Select(p => p.MemberId1 == Id ? p.MemberId2 : p.MemberId1);
}
}
}
Original answer:
The problem is that you break the relation by saving it into one record. If you add an extra level 'Pair' and add 'PairMembers' to that, then it would look like this, assuming each course has different pairs:
Pair:
Id
CourseId
PairMember:
Id
PairId
MemberId
Which will become something like this:
public class Pair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid CourseId { get; set; }
public Course Course { get; set; }
public ICollection<PairMember> PairMembers { get; set; }
}
public class PairMember : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid PairId { get; set; }
[Required]
public Guid MemberId { get; set; }
public Pair Pair { get; set; }
public Member MemberId { get; set; }
}
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public ICollection<PairMember> PairMembers { get; set; }
}
This will allow more than two partners in one pair, but that is something you can prevent in the front. While the backend allows multiple members, the presentation in the front is still member1 and member2.
I didn't test it, but I think this will get you the list of partners:
member.PairMembers
.Select(p => p.Pair.PairMembers.Where(m => m.MemberId != member.Id))

Accessing different models from controllers

I'm pretty new to MVC, it's my first project and I'm trying to learn best practices. I'm using Entity Framework.
Here is the thing:
I have two models, one is for overtime work records and other one for accounting records.
When I create an overtime work record, I want to create an accounting record too. So lets say I created overtime record with 2 hours of work, I want to create an accounting record with value of "hours of work (2) * employees overtime work salary".
I can easily do this in OvertimeController's create method but I'm not sure if I should access other models (Accounting Model) from that controller.
What's the best way to do it?
Here is my models, i'm using code first:
Accounting
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AccountingId { get; set; }
public decimal AccountingType { get; set; }
public decimal AccountingMethod { get; set; }
public string AccountingNote { get; set; }
public decimal AccountingBorc { get; set; }
public decimal AccountingAlacak { get; set; }
public decimal WorkerId { get; set; }
public decimal PhaseId { get; set; }
public virtual Worker Worker { get; set; }
public virtual Phase Phase { get; set; }
Overhours
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OverhourId { get; set; }
public int WorkerId { get; set; }
public int PhaseId { get; set; }
public int OverhourAmount { get; set; }
public DateTime OverhourDate { get; set; }
public virtual Worker Worker { get; set; }
public virtual Phase Phase { get; set; }
Thanks

Navigation property from dependent to principal

I have two Entities
public class Person
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual int ID { get; set; }
public virtual string Code { get; set; }
public virtual int PersonId { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
}
in my business first we create person then we create an employee by selecting a person, while selecting person for the employee i want to select only the persons who are not associated to employee, i couldn't figure how to configure the Employee property in Person Entity
If you are selecting people that aren't related to a specific employee then you shouldn't have a property for that. You should only have link to related entities. Try doing this in LINQ it should get you all people that don't have a relation to an employee.
var people = context.People.Where(x => x.Employee == null);
public class Person
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual int ID { get; set; }
public virtual string Code { get; set; }
public virtual int PersonId { get; set; }
[ForeignKey("PersonId")]
[InverseProperty("Employee")]
public virtual Person Person { get; set; }
}
Think that should do it, inverse property creates the mapping so only needs to be done from one side.
Hope this is what you were looking for.
I figured out an answer, don't know if it's the best!
jobQuery = jobQuery.Where(jb => !Context.Employees.Any(emp => emp.JobId == jb.Id));

Parent and child record added on single MVC View

In ASP.NET MVC 5 and EF6 Code First, i have a case in which a student can have one to many addresses. Now i want to use Student model in View to add both the record Student and Addresses of student. But the problem is i cant add addresses of student, is there any appropriate solution for this solution
Here is the example code
public class Student
{
public Student()
{ }
[Key]
public int StudentID { get; set; }
[Required]
public string Name { get; set; }
public virtual List<Address> Address { get; set; }
}
public class Address
{
public Address()
{
}
[Key]
public int AddressID { get; set; }
[ForeignKey("Student")]
public int StudentID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string PostalCode { get; set; }
public string State { get; set; }
public string City { get; set; }
public string Country { get; set; }
public virtual Student Student { get; set; }
}
Make Listbox for address's and Pass with List that will be really help you and can you paste controller code here?

EF Code First with One-to-Many and Many-to-Many relationships? cause cycles or multiple cascade paths

I have four models that are Family, Mother, Father, Student, I am trying to associate Father& Mother& Student with Family table and Student table associated with Mother and Father tables. Here Family table contains information about the family. Mother and Father Tables contain their personal information, and Student table contains student information + MotherID and FatherID. Which means Family table was the Primary table to Mother and Father, Student table. MotherID of Mother table and FatherID of father table were referenced to Student table.
I am using MVC 4 Entity Framework Code First,
These are my model classes.
public class Family
{
public int FamilyID { get; set; }
public string FamilyName { get; set; }
public virtual ICollection<Mother> Mothers { get; set; }
public virtual ICollection<Father> Fathers { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Mother
{
public int MotherID { get; set; }
public int FamilyID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual ICollection<Student> Students{ get; set; }
}
public class Father
{
public int FatherID { get; set; }
public int FamilyID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
public int StudentID { get; set; }
public int FamilyID { get; set; }
public int MotherID { get; set; }
public int FatherID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual Mother Mothers { get; set; }
public virtual Father Fathers { get; set; }
}
Database Context Class:
public class MYContext:DbContext
{
public DbSet<Family> Families { get; set; }
public DbSet<Mother> Mothers { get; set; }
public DbSet<Father> Fathers { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//base.OnModelCreating(modelBuilder);
}
}
After writing the above code I just ran the below commands on package manager console.
PM> Add-Migration InitialContext It created an InitialContext.cs class for me.
PM> Update-Database -Verbose It give me an error below
Introducing FOREIGN KEY constraint 'FK_dbo.Student_dbo.Mother_MotherID' on table
'Student' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON
UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
What am I doing wrong??
Why I am getting this error??? Please help me some one!
What is the correct way to implement one-to-many and many-to-many relationships using EF code first? Please guide me with this example.
Try adding the [key] annotation immediately above your keys. For instance, for the student, it would look like this...
public class Student
{
[key]
public int StudentID { get; set; }
public int FamilyID { get; set; }
public int MotherID { get; set; }
public int FatherID { get; set; }
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual Mother Mothers { get; set; }
public virtual Father Fathers { get; set; }
}
This will tell you, in detail, how to manage your model from a codefirst perspective.
http://thedatafarm.com/blog/data-access/code-first-entity-framework-4-1-videos-and-articles-on-msdn/
I have found same problem and solution at Entity Framework, Code First modeling and a cyclical reference
The exception was coming from SQL Server DB not from entity framework, that table structure with the same constraints created by hand will be invalid. Foreign key properties of Mother table (Mother.FamilyID) and Father Table (Father.FamilyID), Student table (Student.MotherID) & (Student.FatherID) are not nullable, those representing required relationships and the corresponding columns in the database are also not nullable. So DB is not allowing this model.
If I remove all these properties from model classes then automatically relationship become optional because the navigation properties can be null, So DB treated as this is another model now since the FK columns in the DB can be nullable. Seemingly this is an allowed model.
It worked for me! Use nullable types as follows
Here is the solution for cause cycles or multiple cascade paths issues:
public class Student
{
public int StudentID { get; set; }
public int FamilyID { get; set; }
public int? MotherID { get; set; } //nullable types
public int? FatherID { get; set; } //nullable types
public string FirstName { get; set; }
public string SSN { get; set; }
public virtual Family Families { get; set; }
public virtual Mother Mothers { get; set; }
public virtual Father Fathers { get; set; }
}
Finally my model becomes with foreign key properties which represent optional instead of required relationship.
really very very thanks to # https://stackoverflow.com/users/270591/slauma and
https://stackoverflow.com/users/173937/decibyte for helping me in this type issue.

Resources