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; }
}

См. также