Entity Framework: повторяющиеся записи во многих отношениях
У меня есть первый код корневого кода сущности. Таблицы создаются и данные вставляются. Однако в таблице Club есть дубликаты записей.
Мои операции: -
-
Создание клубов с использованием приложения для создания клуба
-
Создание лиц, использующих приложение для пользователей
Как избежать дублирования записи?
![enter image description here]()
static void Main(string[] args)
{
Database.SetInitializer<NerdDinners>(new MyInitializer());
CreateClubs();
InsertPersons();
}
public static void CreateClubs()
{
string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
using (var db = new NerdDinners(connectionstring))
{
Club club1 = new Club();
club1.ClubName = "club1";
Club club2 = new Club();
club2.ClubName = "club2";
Club club3 = new Club();
club3.ClubName = "club3";
db.Clubs.Add(club1);
db.Clubs.Add(club2);
db.Clubs.Add(club3);
int recordsAffected = db.SaveChanges();
}
}
public static Club GetClubs(string clubName)
{
string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
using (var db = new NerdDinners(connectionstring))
{
//var query = db.Clubs.Where(p => p.ClubName == clubName);
var query = db.Clubs.SingleOrDefault(p => p.ClubName == clubName);
return query;
}
}
public static void InsertPersons()
{
string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
using (var db = new NerdDinners(connectionstring))
{
Club club1 = GetClubs("club1");
Club club2 = GetClubs("club2");
Club club3 = GetClubs("club3");
Person p1 = new Person();
p1.PersonName = "Person1";
Person p2 = new Person();
p2.PersonName = "Person2";
List<Club> clubsForPerson1 = new List<Club>();
clubsForPerson1.Add(club1);
clubsForPerson1.Add(club3);
List<Club> clubsForPerson2 = new List<Club>();
clubsForPerson2.Add(club2);
clubsForPerson2.Add(club3);
p1.Clubs = clubsForPerson1;
p2.Clubs = clubsForPerson2;
db.Persons.Add(p1);
db.Persons.Add(p2);
int recordsAffected = db.SaveChanges();
}
}
Домен
public class Person
{
public int PersonId { get; set; }
public string PersonName { get; set; }
public virtual ICollection<Club> Clubs { get; set; }
}
public class Club
{
public int ClubId { get; set; }
public string ClubName { get; set; }
public virtual ICollection<Person> Members { get; set; }
}
//System.Data.Entity.DbContext is from EntityFramework.dll
public class NerdDinners : System.Data.Entity.DbContext
{
public NerdDinners(string connString): base(connString)
{
}
protected override void OnModelCreating(DbModelBuilder modelbuilder)
{
//Fluent API - Plural Removal
modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<Person> Persons { get; set; }
public DbSet<Club> Clubs { get; set; }
}
Ответы
Ответ 1
Проблема заключается в том, что вы создаете больше контекстов.
Сначала вы создаете клубы. Все в порядке. Но когда вы создаете людей, вы получаете клубы через GetClubs
, но для каждого клуба вы размещаете фактический контекст фреймворка, так что в итоге вы получаете отдельные элементы. В InsertPersons
вы добавляете отдельные члены клуба к новым людям, поэтому в реальном контексте будет считаться, что клубы являются новыми клубами.
Итак, когда вы добавляете клуб в человека, вы фактически создаете новые клубы.
Это потому, что структура сущности отслеживает изменения и управляет сущностями в контексте. Если вы добавите объект в контекст, который его еще не содержит, он будет восприниматься как новый объект.
Собственно, вы должны сделать что-то вроде этого (не проверено):
static void Main(string[] args)
{
Database.SetInitializer<NerdDinners>(new MyInitializer());
string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
using (var db = new NerdDinners(connectionstring))
{
CreateClubs(db);
InsertPersons(db);
}
}
public static void CreateClubs(NerdDinners db)
{
Club club1 = new Club();
club1.ClubName = "club1";
Club club2 = new Club();
club2.ClubName = "club2";
Club club3 = new Club();
club3.ClubName = "club3";
db.Clubs.Add(club1);
db.Clubs.Add(club2);
db.Clubs.Add(club3);
int recordsAffected = db.SaveChanges();
}
public static Club GetClubs(string clubName, NerdDinners db)
{
//var query = db.Clubs.Where(p => p.ClubName == clubName);
var query = db.Clubs.SingleOrDefault(p => p.ClubName == clubName);
return query;
}
public static void InsertPersons(NerdDinners db)
{
Club club1 = GetClubs("club1", db);
Club club2 = GetClubs("club2", db);
Club club3 = GetClubs("club3", db);
Person p1 = new Person();
p1.PersonName = "Person1";
Person p2 = new Person();
p2.PersonName = "Person2";
List<Club> clubsForPerson1 = new List<Club>();
clubsForPerson1.Add(club1);
clubsForPerson1.Add(club3);
List<Club> clubsForPerson2 = new List<Club>();
clubsForPerson2.Add(club2);
clubsForPerson2.Add(club3);
p1.Clubs = clubsForPerson1;
p2.Clubs = clubsForPerson2;
db.Persons.Add(p1);
db.Persons.Add(p2);
int recordsAffected = db.SaveChanges();
}
Конечно, вы должны реорганизовать структуру этого кода, но, пожалуйста, обратите внимание, что для моих операций я использую только один контекст EF.
Ответ 2
Благодаря @PeterPorfy
Также читайте Исключение типа 'System.ObjectDisposedException'
Я использовал
((IObjectContextAdapter)db).ObjectContext.Attach((IEntityWithKey)entity);
для прикрепления объектов из предыдущего контекста.
Один пример использования IEntityWithKey заключается в следующем. Прокомментируйте, если вы видите какие-либо проблемы с этим подходом.
public class Person : IEntityWithKey
{
public int PersonId { get; set; }
public string PersonName { get; set; }
public EntityKey EntityKey { get; set; }
}
См. также