Entity Framework 4/MVC3 navigation properties dilemma - entity-framework

I am trying to figure out how to setup the navigation properties for 2 models (entities) that will generate the SQL tables. The scenario: I have a shipment and a company model/entity. I need to tie 3 properties ClientID¸ ShipperID and ConsigneeID from the Shipment model to point to CompanyID in the Company model. Now what are the correct Navigation Properties for the Shipment model and what the Context is going to look like?
public virtual ICollection< Company > Companies { get; set; }
OR
public virtual Company Company { get; set; }
Here are the 2 models:
public class Shipment
{
public int ShipmentID { get; set; }
public string Name { get; set; }
public DateTime DateStamp { get; set; }
public int ClientID { get; set; }
public int ShipperID { get; set; }
public int ConsigneeID { get; set; }
public virtual ICollection< Company > Companies { get; set; }
OR
public virtual Company Company { get; set; }
}
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
public DateTime DateStamp { get; set; }
public virtual ICollection< Shipment > Shipments { get; set; }
}

You'll need to use some Attributes to accomplish this.
I'm assuming that you have a 1-* relation between shipments and companies.
(A shipment to * Clients/Shippers/Consignees)
Shipment:
public class Shipment
{
public int ShipmentID { get; set; }
public string Name { get; set; }
public DateTime DateStamp { get; set; }
[ForeignKey("Client")]
public int ClientID { get; set; }
[ForeignKey("Shipper")]
public int ShipperID { get; set; }
[ForeignKey("Consignee")]
public int ConsigneeID { get; set; }
public virtual Company Client { get; set; }
public virtual Company Shipper { get; set; }
public virtual Company Consignee { get; set; }
}
Company:
public class Company
{
public int CompanyID { get; set; }
public string Name { get; set; }
public DateTime DateStamp { get; set; }
[InverseProperty("Shipper")]
public virtual ICollection< Shipment > ShipmentsShipped { get; set; }
[InverseProperty("Consignee")]
public virtual ICollection<Shipment> ShipmentsConsigned { get; set; }
[InverseProperty("Client")]
public virtual ICollection<Shipment> ShipmentsOwned { get; set; }
}
The Context:
public class TesteEntityMVCContext : DbContext
{
public DbSet<Shipment> Shipments { get; set; }
public DbSet<Company> Companies { get; set; }
}

if your shipment have many companies you need to use (many to many relationship)
public virtual ICollection< Company > Companies { get; set; }
else if your shipment have only one company you need to use (one to many relationship)
public virtual Company Company { get; set; }
And optionally you can to specify more about the relationship in onModelBuilding event in your dbContext.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Shipment>()
.HasRequired(x => x.Company ) \\..... etc as your requirement

Related

EF code first self reference many to many

In one of business scenario need to create Model in code first approach like
Business has many Vendors
Vendors can belongs to many Businesses
So need to create many to many between Business and Vendors, but Vendor is logically Business itself (self reference). Vendor Model is not exist physically.
How to create BusinessVendor model with many to many relationship with Business itself and separate columns IsActive and VendorType in association table i.e. BusinessVendor?
Update:
public class Business
{
public Business()
{
this.Users = new HashSet<User>();
this.Departments = new HashSet<Department>();
this.Addresses = new HashSet<Address>();
this.BusinessProducts = new HashSet<BusinessProduct>();
this.Vendors = new HashSet<Vendor>();
}
[Key]
public int BusinessId { get; set; }
[Required]
[Display(Name = "Business Name")]
public string Name { get; set; }
[Required]
[Display(Name = "PAN Number")]
public string PAN { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[RegularExpression(#"[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}", ErrorMessage = "Incorrect Email Format")]
public string Email { get; set; }
public string Fax { get; set; }
[Required]
[Display(Name = "Registration Number")]
public string RegistrationNumber { get; set; }
[Required]
[Display(Name ="Business ID")]
public string DisplayName { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Department> Departments { get; set; }
public virtual ICollection<BusinessProduct> BusinessProducts { get; set; }
public virtual ICollection<CategoryOfProduct> ProductCategories { get; set; }
public virtual ICollection<Vendor> Vendors { get; set; }
}
public class Vendor
{
[Key]
public int VendorId { get; set; }
[Required, ForeignKey("Client")]
public int BusinessId { get; set; }
public int VendorTypeId { get; set; }
[ForeignKey("VendorTypeId")]
public virtual VendorType VendorType { get; set; }
public bool IsActive { get; set; }
public virtual Business Client { get; set; }
public virtual ICollection<Business> Businesses { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Business>()
.HasMany(c => c.Vendors)
.WithMany(c => c.Businesses)
.Map(op =>
{
op.MapLeftKey("BusinessId");
op.MapRightKey("VendorId");
op.ToTable("BusinessVendors");
});
}
But now getting issue with Cascade delete as
Introducing FOREIGN KEY constraint
'FK_dbo.BusinessVendors_dbo.Vendors_VendorId' on table
'BusinessVendors' 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.

EF 6 Mapping Complex Composite Keys

I have the following models
public class Company
{
[Key, Column(Order=0)]
public int Id {get;set;}
public string CompanyCode { get; set; }
public string Name { get; set; }
public virtual ICollection<Account> Accounts { get; set; }
public virtual ICollection<Journal> Journals { get; set; }
}
public class Account
{
[Key, Column(Order=0)]
public int Id { get; set; }
[Key, Column(Order=1), ForeignKey("Company")]
public int CompanyId { get; set; }
public int GLAccountNumber { get; set; }
public decimal Balance { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<Journal> Journals { get; set; }
}
public class Journal
{
[Key, Column(Order=0)]
public int Id { get; set; }
[Key, Column(Order=1), ForeignKey("Company")]
public int CompanyId { get; set; }
[ForeignKey("Account")]
public int AccountId { get; set; }
public DateTime EntryDate { get; set; }
public decimal Amount { get; set; }
public virtual Company Company { get; set; }
public virtual Account Account { get; set; }
}
How would I map the relationship between these models, Specifically I cannot figure out how to define the Composite Key in the Journal Model to map to Account By CompanyId, AccountId
You could use fluent APi (my personal preference - clear and less error prone):
modelBuilder.Entity<Journal>()
.HasRequired(e => e.Account)
.WithMany(e => e.Journals)
.HasForeignKey(e => new { e.AccountId, e.CompanyId });
But if you prefer data annotations, then apply the ForeignKey attribute on the navigation property and specify comma separated list of the FK properties:
public class Journal
{
[Key, Column(Order=0)]
public int Id { get; set; }
[Key, Column(Order=1)]
public int CompanyId { get; set; }
public int AccountId { get; set; }
public DateTime EntryDate { get; set; }
public decimal Amount { get; set; }
[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }
[ForeignKey("AccountId,CompanyId")]
public virtual Account Account { get; set; }
}

EF one to many relation

I use EF's code first approach. I have the following three classes:
public class Inquiry
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual ApplicationUser CreatedBy { get; set; }
public virtual Contractor Contractor { get; set; }
public IList<ApplicationUser> InquiryUsers { get; set; }
public IList<InquiryComment> Comments { get; set; }
public IList<HydroTechEmail> Emails { get; set; }
public InquiryState State { get; set; }
public List<string> Attachments { get; set; }
public DateTime? TimeOfCreation { get; set; }
public DateTime? TimeOfModification { get; set; }
}
public class HydroTechEmail
{
public Guid Id { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
public string FromDisplayName { get; set; }
public string FromAddress { get; set; }
public List<string> ToDisplayName { get; set; }
public List<string> ToAddress { get; set; }
public HydroTechEmailState State { get; set; }
public DateTime? ReceivedTime { get; set; }
public virtual List<HydroTechEmailAttachment> Attachments { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
public class ApplicationUser
{
public Guid Id {get;set;}
public string Firstname {get;set;}
public string Lastname {get;set;}
}
I thought EF will generate some intermediate classes for relation Inquiry -> Many Emails and Inquiry -> Many Application Users. Instead it created a foreign keys in ApplicationUser and HydroTechEmail classes to Inquiry class. How should I create this one to many relations?
The strange is that for Comments it created an intermediate table named InquiryComments.
Entity Framework will only generate intermediate tables for many-to-many relationships.
For one-to-many relationships, no intermediate tables will be created because it is not necessary.

What kind of relationship do I need

I am stuck on figuring this out. MVC 5, EntityFramework
My project revolves around a Job. Every Job has multiple ChangeOrders. I have that setup fine. A Job has one Customer. That works fine as well. my problem is with the Customer Employees. The Customer class has a one-to-many relationship with the CustomerEmployee class. Every Customer Employee has a basic properties plus a Role property. Super,PM,Accountant, or Admin. Well when I create a job, I need to select a CustomerEmployee Admin/PM etc...
What relationship would this be? A many-to-many relationship? In my mind, the Job class would need to have a CustomerEmployeeSuperId, CustomerEmployeePMId, CustomerEmployeeAdminId and CustomerEmployeeAccountantId.
Because right now all it has is CustomerEmployeeId
How do I do this?
Current Setup
public class Job
{
//job
public int JobId { get; set; }
public int? JobNumber { get; set; }
public string JobName { get; set; }
public string JobDescription { get; set; }
public int? GeoAreaId { get; set; }
public virtual JobMisc.GeoArea GeoArea { get; set; }
public int? JobClassId { get; set; }
public virtual JobMisc.JobClass JobClass { get; set; }
public int? JobTypeId { get; set; }
public virtual JobMisc.JobType JobType { get; set; }
public Int64? CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<ChangeOrder> ChangeOrders { get; set; }
public virtual ICollection<PurchaseOrder> PurchaseOrders { get; set; }
public int? CustomerEmployeeId { get; set; }
public virtual ICollection<CustomerEmployee> CustomerEmployees { get; set; }
}
public class Customer
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public Int64 CustomerId { get; set; }
public string CustomerName { get; set; }
public Int64? CustomerPhoneNumber { get; set; }
public Int64? CustomerFaxNumber { get; set; }
public string CustomerAddress { get; set; }
public string CustomerCity { get; set; }
public string CustomerState { get; set; }
public int? CustomerZipcode { get; set; }
public string CustomerWebsite { get; set; }
public string CustomerOtherShit { get; set; }
public bool? CustomerIsHidden { get; set; }
public virtual ICollection<CustomerEmployee> CustomerEmployees { get; set; }
public List<Job> Jobs { get; set; }
}
public class CustomerEmployee
{
[Key]
public int CustomerEmployeeId { get; set; }
public string CustomerEmployeeFirstName { get; set; }
public string CustomerEmployeeLastName { get; set; }
public string CustomerEmployeeEmail { get; set; }
public Int64? CustomerEmployeePhoneNumber { get; set; }
public Int64? CustomerEmployeeCellNumber { get; set; }
public Int64? CustomerEmployeeFaxNumber { get; set; }
public bool? CustomerEmployeeIsHidden { get; set; }
public string CustomerEmployeeRole { get; set; }
public Int64? CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public int? JobId { get; set; }
public virtual ICollection<Job> Jobs { get; set; }
}
Well, for the individual job, it would be a one to many relationship. For multiple jobs, it could be many to many.
Is it possible that an employee who is an Admin might also be pressed into service as a tester for certain jobs?
I'd recommend created a child table for JobRoles, one that links to the JobID, a CustomerEmployeeID, and a JobRoleID (assuming the possibility of the JobRoles being flexible).
Hope this helps...

Many-to-many relationship with POCO classes in Entity Framework (DB first)

I have a context that looks like this:
public DbSet<User> Users { get; set; }
public DbSet<AccessGroup> AccessGroups { get; set; }
public DbSet<UserAccessGroup> UsersAccessGroups { get; set; }
The database has three tables:
Users [Pk = Id, ...]
AccessGroups [Pk = Id, ...]
UsersAccessGroups [Pk = Id, Fk = UserId, Fk = AccessGroupId, ...] (Has columns for created by and when as well)
We have three classes:
public class User
{
public virtual int Id { get; set; }
public virtual ICollection<UserAccessGroup> UsersAccessGroups { get; set; }
// Some more..
}
public class AccessGroup
{
public virtual int Id { get; set; }
public virtual ICollection<UserAccessGroup> UsersAccessGroups { get; set; }
// Some more..
}
[Table("UsersAccessGroups")]
public class UserAccessGroup
{
public virtual int Id { get; set; }
public virtual int UserId { get; set; }
public virtual int AccessGroupId { get; set; }
public virtual int CreatedByUserId { get; set; }
public virtual DateTime CreatedAt { get; set; }
public virtual User User { get; set; }
public virtual AccessGroup AccessGroup { get; set; }
public virtual User CreatedByUser { get; set; }
}
I would like to be able to use a user object like this:
var user = Context.Users.Select(x => x);
var accessGroup = user.UsersAccessGroups.Select(x => x.AccessGroup).ToList();
The second row doesn't not work however. I get error saying "Invalid column name User_Id"
The same code works when I have a one-to-one relationship (like CreatedByUser).
I have also tried something like this:
Context.Users.Include("UsersAccessGroups")
.Include("UsersAccessGroups.AccessGroup")
.Include("UsersAccessGroups.User").Select(...);
but I get the same problem.
Is it possible to get this to work, or do I have to do it differently somehow?
You'll need to specify the foreign key for CreatedByUser, since EF will not be able to map that by convention.
[Table("UsersAccessGroups")]
public class UserAccessGroup
{
public virtual int Id { get; set; }
public virtual int UserId { get; set; }
public virtual int AccessGroupId { get; set; }
public virtual int CreatedByUserId { get; set; }
public virtual DateTime CreatedAt { get; set; }
public virtual User User { get; set; }
public virtual AccessGroup AccessGroup { get; set; }
[ForeignKey("CreatedByUserId")]
public virtual User CreatedByUser { get; set; }
}