I have a small model created using code-first approach - a class City
which contains only information about city name.
public class City
{
public City()
{
Posts = new List<Post>();
}
public City(string cityName)
{
Name = cityName;
}
public virtual ICollection<Post> Posts { get; private set; }
public int Id { get; set; }
public string Name { get; private set; }
}
A Post
class represents combination of zip code and city reference
public class Post
{
public virtual City City { get; set; }
public int Id { get; set; }
public string ZipCode { get; set; }
}
both entities have their sets defined in context as their configurations
public DbSet<City> Cities { get; set; }
public DbSet<Post> Posts { get; set; }
modelBuilder.Configurations.Add(new CityMap());
modelBuilder.Configurations.Add(new PostMap());
public class CityMap : EntityTypeConfiguration<City>
{
public CityMap()
{
// Primary Key
HasKey(t => t.Id);
// Properties
// Table & Column Mappings
ToTable("City");
Property(t => t.Id).HasColumnName("Id");
Property(t => t.Name).HasColumnName("Name");
}
}
public class PostMap : EntityTypeConfiguration<Post>
{
public PostMap()
{
// Primary Key
HasKey(t => t.Id);
// Properties
// Table & Column Mappings
ToTable("Post");
Property(t => t.Id).HasColumnName("Id");
Property(t => t.ZipCode).HasColumnName("ZipCode");
// Relationships
HasRequired(t => t.City)
.WithMany(t => t.Posts)
.Map(map=>map.MapKey("CityId"));
}
}
I've created class for manipulation with those objects with static methods which get or creates objects and return them to caller.
private static City GetCity(string cityName)
{
City city;
using (var db = new DbContext())
{
city = db.Cities.SingleOrDefault(c => c.Name == cityName);
if (city == null)
{
city = new City(cityName);
db.Cities.Add(city);
db.SaveChanges();
}
}
return city;
}
private static Post GetPost(string zipCode, string cityName)
{
Post post;
City city = GetCity(cityName);
using (var db = new DbContext())
{
post = db.Posts.SingleOrDefault(p => p.City.Id == city.Id && p.ZipCode == zipCode);
if (post == null)
{
post = new Post { City = city, ZipCode = zipCode };
// State of city is unchanged
db.Posts.Add(post);
// State of city is Added
db.SaveChanges();
}
}
return post;
}
Imagine, that I call method
GetPost("11000","Prague");
method GetCity
is started and if not exists, method creates a city
and then calls the SaveChanges()
method.
If I set returned city
entity to new Post
instance, Entity Framework generates a second insert for the same city
.
How can I avoid this behavior? I want to only insert new post
entity with referenced city
created or loaded in previous step.
You need to set the
State
of your city when you attach it to unchanged