So I'm trying to create a new Order, and Orders have both properties Customer and Restaurant which both have Address, with State that refers to a lookup table (an table created off an enum).
But when I try to add a new Order where both the Restaurant and Customer addresses have the same State I get the error "The instance of entity type 'State' cannot be tracked because another instance with the key value '{Id: IL}' is already being tracked" when I do _context.Attach(order);
How do I get entity to understand that order.Restaurant.Address.State and order.Customer.Address.State are not that same entity even if they're identical?
public class Order
{
[Key]
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public decimal Price { get; set; }
public decimal Tip { get; set; }
public bool HasTippedRecently { get; set; }
public Restaurant? Restaurant { get; set; }
public Customer? Customer { get; set; }
public Driver? Driver { get; set; }
}
public class Customer
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public Address Address { get; set; } = new Address();
public Phone Phone { get; set; } = new Phone();
}
public class Restaurant
{
[Key]
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public Address Address { get; set; } = new Address();
public Phone Phone { get; set; } = new Phone();
}
public class Address
{
[Key]
public int Id { get; set; }
public string? Street { get; set; }
public string? Street2 { get; set; }
public string? City { get; set; }
public string? Zip { get; set; }
public State State { get; set; } = new State();
}
public enum StateId : int
{
[Description("Alabama")]
AL = 1,
[Description("Alaska")]
AK = 2,
[Description("Arkansas")]
AR = 3,
[Description("Arizona")]
AZ = 4,
[Description("California")]
CA = 5,
[Description("Colorado")]
CO = 6,
[Description("Connecticut")]
CT = 7,
[Description("D.C.")]
DC = 8,
[Description("Delaware")]
DE = 9,
[Description("Florida")]
FL = 10,
[Description("Georgia")]
GA = 11,
[Description("Hawaii")]
HI = 12,
[Description("Iowa")]
IA = 13,
[Description("Idaho")]
ID = 14,
[Description("Illinois")]
IL = 15,
[Description("Indiana")]
IN = 16,
[Description("Kansas")]
KS = 17,
[Description("Kentucky")]
KY = 18,
[Description("Louisiana")]
LA = 19,
[Description("Massachusetts")]
MA = 20,
[Description("Maryland")]
MD = 21,
[Description("Maine")]
ME = 22,
[Description("Michigan")]
MI = 23,
[Description("Minnesota")]
MN = 24,
[Description("Missouri")]
MO = 25,
[Description("Mississippi")]
MS = 26,
[Description("Montana")]
MT = 27,
[Description("North Carolina")]
NC = 28,
[Description("North Dakota")]
ND = 29,
[Description("Nebraska")]
NE = 30,
[Description("New Hampshire")]
NH = 31,
[Description("New Jersey")]
NJ = 32,
[Description("New Mexico")]
NM = 33,
[Description("Nevada")]
NV = 34,
[Description("New York")]
NY = 35,
[Description("Oklahoma")]
OK = 36,
[Description("Ohio")]
OH = 37,
[Description("Oregon")]
OR = 38,
[Description("Pennsylvania")]
PA = 39,
[Description("Rhode Island")]
RI = 40,
[Description("South Carolina")]
SC = 41,
[Description("South Dakota")]
SD = 42,
[Description("Tennessee")]
TN = 43,
[Description("Texas")]
TX = 44,
[Description("Utah")]
UT = 45,
[Description("Virginia")]
VA = 46,
[Description("Vermont")]
VT = 47,
[Description("Washington")]
WA = 48,
[Description("Wisconsin")]
WI = 49,
[Description("West Virginia")]
WV = 50,
[Description("Wyoming")]
WY = 51
}
public class State
{
[Key]
public StateId Id { get; set; }
public string? StateAbbreviation { get; set; }
}
added from my context
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<State>().HasData(
Enum.GetValues(typeof(StateId))
.Cast<StateId>()
.Select(st => new State()
{
Id = st,
StateAbbreviation = st.ToString(),
}));
}
CodePudding user response:
You are trying to use Entity Splitting
, which is not supported by the current version of EF Core (Issue 620). Concerning Arthur Vickers's comment; Possibly we may have it on EF Core 7
Nevertheless, I believe you can consider using Owned Entity Types or change the way you designed your code first and entities.
CodePudding user response:
You write that the addresses "have the same State" but then in second paragraph "order.Restaurant.Address.State and order.Customer.Address.State are not that same entity even if they're identical". From EF Core perspective you can only have a single tracked entity for a specific PK (IL/15 in your case), and there are numerous ways to achieve this.
Looking at your code above, I'd suggest a solution where you only work with foreign keys when adding new data.
Add the foreign key to your model (by convention it is the same name as the property but with Id suffix).
public class Address
{
[Key]
public int Id { get; set; }
public string? Street { get; set; }
public string? Street2 { get; set; }
public string? City { get; set; }
public string? Zip { get; set; }
public State State { get; set; } = new State();
// new fk property by convention
public int StateId { get; set; }
}
When constructing the Address
object, only set the StateId
foreign key (to IL/15). Do not set the State
object, it will be automatically set by EF Core to the tracked entity pointed to by the foreign key. (which you should already have in your database thanks to the seeding done by HasData
)