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.
Related
in my project (Asp.net Core Web Api) I have the tables "Truck" and "UserAccount with a one to many relashionship.
[Table("UserAccount")]
public class UserAccount : BaseClass
{
// Foreign Keys
[ForeignKey(nameof(UserAccountType))]
public int UserAccountTypeId { get; set; }
[ForeignKey(nameof(Gender))]
public int GenderId { get; set; }
[ForeignKey(nameof(Truck))]
public int TruckId { get; set; }
// Properties
public string LastName { get; set; }
public string FirstName { get; set; }
public string UserName { get; set; }
[DataType(DataType.EmailAddress)]
public string Mail { get; set; }
public string Login { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
// Navigation Properties
[IgnoreDataMember]
public virtual Gender Gender { get; set; }
//public virtual Truck Truck { get; set; }
[IgnoreDataMember]
public virtual UserAccountType UserAccountType { get; set; }
public Truck Truck { get; set; }
}
[Table("Truck")]
public class Truck : BaseClass
{
// Foreign Keys
// Properties
[Column(Order = 3)]
public string Name { get; set; }
[DataType(DataType.EmailAddress)]
[Column(Order = 4)]
public string Mail { get; set; }
[Column(Order = 5)]
public string Phone { get; set; }
[Column(Order = 6)]
public string VATNumber { get; set; }
// Navigation Properties
public virtual ICollection<TruckFoodType> TruckFoodTypes { get; set; }
public virtual ICollection<TruckOption> TruckOptions { get; set; }
public ICollection<UserAccount> UserAccounts { get; set; }
}
In the method OnModelCreation into my ApplicationDbContex file I have this to create the one to many relashionship:
modelBuilder.Entity<UserAccount>()
.HasOne<Truck>(u => u.Truck)
.WithMany(t => t.UserAccounts)
.HasForeignKey(u => u.TruckId);
But when I try to populate the UserAccount table I have this error message :
"Merge instruction is in conflict with "FK_User_Account_TruckId". This conflict occurse in the database xxx table dbo.Truck column Id" (Sorry, Comes from a french translation)
I don't hunderstand why.
Can somebody help me?
Thanks
OK, stupid mistake. In some cases the TruckId field from the User Account table can be null. So I added a "?" to this fields like this : public int? TruckId { get; set; } Sorry for inconvenience
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; }
}
I am trying to link two models with One to One relationship
the classes are following:
public class Customer : BaseEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[ForeignKey("Account")]
public int AccountId { get; set; }
public virtual Account Account { get; set; }
[Required(AllowEmptyStrings = false)]
public string Address { get; set; }
[Required(AllowEmptyStrings = false)]
public string PublicName { get; set; }
[Required]
public int UserId { get; set; }
[ForeignKey("Id")]
[InverseProperty("Customer")]
public virtual User User { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
public class User : BaseEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(32)]
[RegularExpression(#"^[\w]+(\.?[\w\d_]+)?$")]
public string Login { get; set; }
[Required]
[MinLength(6)]
[DataType(DataType.Password)]
[RegularExpression(#"^[\w]+(\.?[\w\d_]+)?$")]
public string Password { get; set; }
[Required]
[StringLength(32)]
[DataType(DataType.EmailAddress)]
[RegularExpression(#"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")]
public string Email { get; set; }
[Required]
public string Firstname { get; set; }
[Required]
public string Lastname { get; set; }
[MaxLength(256)]
public string ProfilePhoto { get; set; }
[Required]
[ForeignKey("Account")]
public int AccountId { get; set; }
[Required]
public virtual Account Account { get; set; }
[InverseProperty("User")]
public virtual ICollection<Rate> Rates { get; set; }
public int CustomerId { get; set; }
[ForeignKey("Id")]
[InverseProperty("User")]
public virtual Customer Customer { get; set; }
}
i searched did not but found solution for doing than ONLY with attributes. can anybody help me with that?
Thanks in advance!
The mistake that you're making is that you have both tables pointing to each other as having a foreign key relationship with the other. You have to pick one table as the base table and the other as being the one that has the FK in it. If you want the User table to be the base then you would do the following:
On the User class: Remove the [ForeignKey] and [InverseProperty] attributes from Customer.
On the Customer class:
[Key, ForeignKey("User")]
public int Id { get; set; }
//Other fields
public virtual User User { get; set; }
I’m pretty new to EF and I have a little problem.
I just want to delete an item in my database. I’m using SQL Server 2012 Express, VS2012, AdventureWorks 2012.
The query that I execute is the following:
context = new AWEntities();
var removedItem = context.Addresses
.Include("StateProvince")
.Include("SalesOrderHeaders")
.Include("BusinessEntityAddresses").Single(d => d.AddressID == 11);
context.Addresses.Remove(removedItem);
context.SaveChanges();
The error that I get is
The DELETE statement conflicted with the REFERENCE constraint "FK_SalesOrderHeader_Address_ShipToAddressID". The conflict occurred in database "AdventureWorks2012", table "Sales.SalesOrderHeader", column 'ShipToAddressID'.
The statement has been terminated.
Is this actually a good way to delete items and the according entries in the other tables?
Please point me into the right direction.
public partial class Address
{
public Address()
{
this.BusinessEntityAddresses = new HashSet<BusinessEntityAddress>();
this.SalesOrderHeaders = new HashSet<SalesOrderHeader>();
}
public int AddressID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public int StateProvinceID { get; set; }
public string PostalCode { get; set; }
public System.Data.Spatial.DbGeography SpatialLocation { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual StateProvince StateProvince { get; set; }
public virtual ICollection<BusinessEntityAddress> BusinessEntityAddresses { get; set; }
public virtual ICollection<SalesOrderHeader> SalesOrderHeaders { get; set; }
}
public partial class StateProvince
{
public StateProvince()
{
this.Addresses = new HashSet<Address>();
this.SalesTaxRates = new HashSet<SalesTaxRate>();
}
public int StateProvinceID { get; set; }
public string StateProvinceCode { get; set; }
public string CountryRegionCode { get; set; }
public bool IsOnlyStateProvinceFlag { get; set; }
public string Name { get; set; }
public int TerritoryID { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual CountryRegion CountryRegion { get; set; }
public virtual ICollection<SalesTaxRate> SalesTaxRates { get; set; }
public virtual SalesTerritory SalesTerritory { get; set; }
}
}
public partial class BusinessEntityAddress
{
public int BusinessEntityID { get; set; }
public int AddressID { get; set; }
public int AddressTypeID { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual Address Address { get; set; }
public virtual AddressType AddressType { get; set; }
public virtual BusinessEntity BusinessEntity { get; set; }
}
public partial class SalesOrderHeader
{
public SalesOrderHeader()
{
this.SalesOrderDetails = new HashSet<SalesOrderDetail>();
this.SalesOrderHeaderSalesReasons = new HashSet<SalesOrderHeaderSalesReason>();
}
public int SalesOrderID { get; set; }
public byte RevisionNumber { get; set; }
public System.DateTime OrderDate { get; set; }
public System.DateTime DueDate { get; set; }
public Nullable<System.DateTime> ShipDate { get; set; }
public byte Status { get; set; }
public bool OnlineOrderFlag { get; set; }
public string SalesOrderNumber { get; set; }
public string PurchaseOrderNumber { get; set; }
public string AccountNumber { get; set; }
public int CustomerID { get; set; }
public Nullable<int> SalesPersonID { get; set; }
public Nullable<int> TerritoryID { get; set; }
public int BillToAddressID { get; set; }
public int ShipToAddressID { get; set; }
public int ShipMethodID { get; set; }
public Nullable<int> CreditCardID { get; set; }
public string CreditCardApprovalCode { get; set; }
public Nullable<int> CurrencyRateID { get; set; }
public decimal SubTotal { get; set; }
public decimal TaxAmt { get; set; }
public decimal Freight { get; set; }
public decimal TotalDue { get; set; }
public string Comment { get; set; }
public System.Guid rowguid { get; set; }
public System.DateTime ModifiedDate { get; set; }
public virtual Address Address { get; set; }
public virtual ShipMethod ShipMethod { get; set; }
public virtual CreditCard CreditCard { get; set; }
public virtual CurrencyRate CurrencyRate { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<SalesOrderDetail> SalesOrderDetails { get; set; }
public virtual SalesPerson SalesPerson { get; set; }
public virtual SalesTerritory SalesTerritory { get; set; }
public virtual ICollection<SalesOrderHeaderSalesReason> SalesOrderHeaderSalesReasons { get; set; }
}
Can't really tell much from what you have said, but you may benefit from looking into using the DbModelBuilder to solve cascade issues:
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOptional(x => x.Parent)
.WillCascadeOnDelete(true);
Again, would need more information about your model structure to determine if this is the right approach.
Either that or in your delete method, remove any children first, and then remove the parent.
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOptional(x => x.Parent)
.WillCascadeOnDelete(true);
or use Include
var adv = db.Adv.Include(b => b.Features)
.Include(b => b.AdvDetails)
.Include(b => b.AdvGallery)
.FirstOrDefault(b => b.Id == id);
db.Adv.Remove(adv);
for .HasMany(...).WithMany(...) Include is ok
You can resolve this issue on SQL side
Method 1 :
First, you need to find on which table this FK constraint has been defined, through using Replication monitor.
Right click on that FK, click Modify, you should get popup box like one shown below.
From the popup box, Select Cascade for del.
Method 2 :
set ON DELETE CASCADE in sql at the end of constraint.
In EF Core the syntax in builder is as follows:
builder.HasOne(b => b.Parent )
.WithMany(a => a.Children)
.OnDelete(DeleteBehavior.Cascade);
https://learn.microsoft.com/en-us/ef/core/saving/cascade-delete
I got this error when I created Entity B, that referenced Entity A, and then tried to delete Entity A. SQL/EF did not allow me to leave that dangling Id reference, since the objcet no longer existed. Cascading deletes would solve this, but I wanted B to persist. So I have to remove the reference from B before deleting A:
var existingContractApprovers = _repo.Query<ChangeOrderApproverForContract>().Where(coafc => coafc.ContractId == key).ToList();
//remove refs to contract approvers to preserve data integrity
foreach(var contractApp in existingContractApprovers)
{
var associatedChangeOrderApprovers = _repo.Query<ChangeOrderApprover>().AsNoTracking().Where(coafc => coafc.ChangeOrderApproverForContractId == contractApp.Id).ToList();
foreach(var coApp in associatedChangeOrderApprovers)
{
_repo.Edit(coApp);
coApp.ChangeOrderApproverForContractId = null;
}
}
_repo.SaveChanges();
//remove the contract approvers
foreach (var contractApp in existingContractApprovers)
{
_repo.Delete(contractApp);
}
_repo.SaveChanges();
You can do this in EF Core.
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOne(s => s.Parent)
.OnDelete(DeleteBehavior.Cascade);
The safer alternative is to make sure all children are deleted before deleting the parent. You should cascade on delete only if you are completely aware of how your entities relate. For example, you could have lots of orders connected to
a certain category in your e-commerce store. Once the category is deleted, all the orders and any entity whose foreign keys are connected to this parent category will be gone.
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