EF4.1 код первый один ко многим сам ссылки - PullRequest
4 голосов
/ 22 сентября 2011

Я пытаюсь сначала сделать ссылку на себя, используя код EF4.1. Моя сущность выглядит так

public class Site
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Sitename { get; set; }

    public virtual Site ChildSite { get; set; }
    public virtual ICollection<Site> ChildSites { get; set; }
}

И в моем контексте класса я делаю это, чтобы сделать ссылку на себя

modelBuilder.Entity<Site>()
    .HasOptional(s => s.ChildSite)
    .WithMany(s => s.ChildSites)
    .HasForeignKey(s => s.ParentId);

Но когда я пытаюсь добавить фиктивные данные в свою базу данных с этим кодом

var sites = new List<Site>
{
    new Site { ParentId = 0, Sitename = "Top 1" },
    new Site { ParentId = 0, Sitename = "Top 2" },
    new Site { ParentId = 0, Sitename = "Top 3" },
    new Site { ParentId = 0, Sitename = "Top 4" },
    new Site { ParentId = 1, Sitename = "Sub 1_5" },
    new Site { ParentId = 1, Sitename = "Sub 1_6" },
    new Site { ParentId = 1, Sitename = "Sub 1_7" },
    new Site { ParentId = 1, Sitename = "Sub 1_8" },
    new Site { ParentId = 2, Sitename = "Sub 2_9" },
    new Site { ParentId = 2, Sitename = "Sub 2_10" },
    new Site { ParentId = 2, Sitename = "Sub 2_11" },
    new Site { ParentId = 2, Sitename = "Sub 2_12" },
    new Site { ParentId = 3, Sitename = "Sub 3_13" },
    new Site { ParentId = 3, Sitename = "Sub 3_14" },
    new Site { ParentId = 3, Sitename = "Sub 3_15" },
    new Site { ParentId = 3, Sitename = "Sub 3_16" },
    new Site { ParentId = 4, Sitename = "Sub 4_17" },
    new Site { ParentId = 4, Sitename = "Sub 4_18" },
    new Site { ParentId = 4, Sitename = "Sub 4_19" },
    new Site { ParentId = 4, Sitename = "Sub 4_20" }
};
sites.ForEach(s => context.Sites.Add(s));
context.SaveChanges();

Я получаю эту ошибку:

Невозможно определить основной конец Отношение Cms.Model.Site_ChildSite. Несколько добавленных объектов могут имеют одинаковый первичный ключ.

Что мне здесь не хватает?

Редактировать:

Вот решение моей проблемы. Я удалил public virtual Site ChildSite { get; set; } из сущности

public class Site
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Sitename { get; set; }

    public virtual ICollection<Site> ChildSites { get; set; }
}

Затем я изменил modelBuilder на этот

modelBuilder.Entity<Site>()
    .HasMany(s => s.ChildSites)
    .WithOptional()
    .HasForeignKey(s => s.ParentId);

Поскольку создается впечатление, что автоматическое создание базы данных не работает, я пошел дальше и сам создал таблицу, как эта

int Id, not null, primary key
int ParentId, null
string Sitename, null

И все работает так, как я хочу.

2-е редактирование

И последний шаг для автоматической генерации фиктивных данных.

var parent1 = new Site
{
    Sitename = "Top 1",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 1_5"},
            new Site {Sitename = "Sub 1_6"},
            new Site {Sitename = "Sub 1_7"},
            new Site {Sitename = "Sub 1_8"}
        }
};

ect . . . 

context.Sites.Add(parent1);
context.SaveChanges();

См. Ответ Слаумы ниже

Ответы [ 4 ]

3 голосов
/ 20 октября 2011

У меня другая модель, но я опубликую то, что было необходимо в моем случае, и она отлично работает с EF4.1 на MVC 3:

Модель

public class Page
{
    public int Id { get; set; }
    public virtual string Title { get; set; }

    public int? ParentId { get; set; }
    public virtual Page Parent { get; set; }
    public virtual ICollection<Page> Children { get; set; }
}

База данных (использование свободного API)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     modelBuilder.Entity<Page>()
                 .HasOptional(s => s.Parent)
                 .WithMany(s => s.Children)
                 .HasForeignKey(s => s.ParentId);
}

Initializer

var page1 = new Page()
{
     Title = "title"
};

context.Pages.Add(page1);

var page2 = new Page()
{
      Parent = page1,
      Title = "title2",
};

context.Pages.Add(page2);
2 голосов
/ 22 сентября 2011

Ваше отображение верно, и вам не нужно удалять свойство ChildSite. Вы просто не можете использовать свойства внешнего ключа, когда создаете свои сущности и «угадываете», какими будут эти автоматически сгенерированные числа после того, как сущности сохранены, и используете эти числа в тех же сущностях, которые хранятся.

Следующее вместо этого должно работать и создавать ожидаемые строки в базе данных:

var parent1 = new Site
{
    Sitename = "Top 1",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 1_5"},
            new Site {Sitename = "Sub 1_6"},
            new Site {Sitename = "Sub 1_7"},
            new Site {Sitename = "Sub 1_8"}
        }
};
var parent2 = new Site
{
    Sitename = "Top 2",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 2_9"},
            new Site {Sitename = "Sub 2_10"},
            new Site {Sitename = "Sub 2_11"},
            new Site {Sitename = "Sub 2_12"}
        }
};
var parent3 = new Site
{
    Sitename = "Top 3",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 3_13"},
            new Site {Sitename = "Sub 3_14"},
            new Site {Sitename = "Sub 3_15"},
            new Site {Sitename = "Sub 3_16"}
        }
};
var parent4 = new Site
{
    Sitename = "Top 4",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 4_17"},
            new Site {Sitename = "Sub 4_18"},
            new Site {Sitename = "Sub 4_19"},
            new Site {Sitename = "Sub 4_20"}
        }
};
context.Sites.Add(parent1);
context.Sites.Add(parent2);
context.Sites.Add(parent3);
context.Sites.Add(parent4);
context.SaveChanges();

Редактировать

Если сущности, представленные внешним ключом, существуют в БД, вы можете использовать его, например:

var site = context.Sites.Single(s => s.Sitename == "Top 1");
site.ParentId = 4; // set a parent for "Top 1"
context.SaveChanges();

Добавить нового ребенка:

var site = context.Sites.Single(s => s.Sitename == "Top 1");
site.ChildSites.Add(new Site { Sitename = "Sub 1_9" });
context.SaveChanges();

Удалить ребенка:

var site = context.Sites.Single(s => s.Sitename == "Top 1");
// works because of lazy loading
var childToRemove = site.ChildSites.Single(s => s.Sitename == "Sub 1_9");
site.ChildSites.Remove(childToRemove);
context.SaveChanges();

и т.д.

0 голосов
/ 22 сентября 2011

Прежде всего - не указывайте идентификатор - я думаю, что база данных отвечает за добавление автономных номеров к вашим сущностям.

Попробуйте вместо этого заполнить вашу базу данных:

var top1 = new Site { Sitename = "Top 1" };
var sub15 = new Site { ChildSite = top1 , Sitename = "Sub 1_5" };
var sub16 = new Site { ChildSite = top1 , Sitename = "Sub 1_6" };
var sub17 = new Site { ChildSite = top1 , Sitename = "Sub 1_7" };
...
context.Sites.Add(top1);

var top2 = new Site { Sitename = "Top 2" };
var sub29 = new Site { ChildSite = top2 , Sitename = "Sub 2_9" };
var sub210 = new Site { ChildSite = top2 , Sitename = "Sub 2_10" };
var sub211 = new Site { ChildSite = top2 , Sitename = "Sub 2_11" };
....
context.Sites.Add(top2);

....
context.SaveChanges();

Далее: я думаю, вам следует вызвать ваш ChildSite для ParentSite, чтобы сделать код более легким для чтения:

var top1 = new Site { Sitename = "Top 1" };
var sub15 = new Site { ParentSite = top1 , Sitename = "Sub 1_5" };
var sub16 = new Site { ParentSite = top1 , Sitename = "Sub 1_6" };
var sub17 = new Site { ParentSite = top1 , Sitename = "Sub 1_7" };
...
context.Sites.Add(top1);

var top2 = new Site { Sitename = "Top 2" };
var sub29 = new Site { ParentSite = top2 , Sitename = "Sub 2_9" };
var sub210 = new Site { ParentSite = top2 , Sitename = "Sub 2_10" };
var sub211 = new Site { ParentSite = top2 , Sitename = "Sub 2_11" };
....
context.Sites.Add(top2);

....
context.SaveChanges();
0 голосов
/ 22 сентября 2011

Не знаю, для чего нужно хранить коллекцию ChildSite и одну ChildSites для сайта. Попробуйте эту конфигурацию.

public class Site
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
     public virtual  Site Parent { get; set; }
    public string Sitename { get; set; }

    public virtual ICollection<Site> ChildSites { get; set; }
}

modelBuilder.Entity<Site>()
    .HasOptional(s => s.Parent)
    .WithMany(s => s.ChildSites)
    .HasForeignKey(s => s.ParentId);

Редактировать И когда вы вставляете, вам нужно сделать так.

 site s1=   new Site { ParentId = 0, Sitename = "Top 1" };
 site s2=   new Site { ParentId = 0, Sitename = "Top 2" };
 site s3=   new Site { ParentId = 0, Sitename = "Top 3" };
//....
 site s4=  new Site { Parent = s1, Sitename = "Sub 1_5"};
...