Самоссылающийся код рекурсивных отношений «многие ко многим» сначала Entity Framework

Я вообще не могу заставить эту работу работать

class Member
{
    public virtual IList<Member> Friends { get; set; }
    [Key]
    public int MemberId { get; set; }
    public string Name{ get; set; }
}

Я пытался добавить Mappings, но тщетно. Есть ли способ сделать это с CTP5?


person Korayem    schedule 26.02.2011    source источник
comment
Я не думаю, что это относится в первую очередь к коду, но проверьте это сообщение вне.   -  person Bala R    schedule 26.02.2011


Ответы (5)


По соглашению Code First будет воспринимать однонаправленные ассоциации как один ко многим. Поэтому вам нужно использовать свободный API, чтобы сообщить Code First, что вы хотите иметь ассоциацию со ссылками на многие ко многим:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Member>().HasMany(m => m.Friends).WithMany().Map(m =>
        {
            m.MapLeftKey("MemberId");
            m.MapRightKey("FriendId");
            m.ToTable("MembersFriends");
        }
    );
}
person Morteza Manavi    schedule 26.02.2011
comment
Мортеза, я слежу за тобой здесь и в твоем блоге. Это работает безупречно! хотя результирующая таблица называется [MemberMembers], что странно, но это будет исправлено в RTM. Спасибо друг! - person Korayem; 27.02.2011
comment
привет, мне нужно знать, как мы можем использовать множественные ссылки на себя. например, в том же примере кода; общедоступный виртуальный IList‹Member› Friends { get; набор; } общедоступный виртуальный IList‹Member› Parents { get; набор; } - person Nuri YILMAZ; 20.04.2011
comment
Это сработало отлично, спасибо. Знаете ли вы, чтобы было указано имя создаваемой таблицы «многие ко многим»? Элемент MemberMembers работает нормально, но выглядит некрасиво. - person Mike Chamberlain; 07.05.2013
comment
Я сделал именно то, что вы объяснили, но когда я запрашиваю друзей пользователя, я получаю друзей только из таблицы присоединения, где пользователь находится в левом столбце. - person rauchmelder; 12.07.2019
comment
@Morteza Когда я добавляю HasMany, у меня нет возможности связать WithMany, - person Tarek; 29.11.2019
comment
Как мне сделать это в последней версии ядра EF - person Peter; 13.02.2020

Если я прав, вы можете повлиять на имя таблицы «многие ко многим» с помощью этого кода:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Member>().HasMany(m => m.Friends).WithMany().Map(m =>
        {
            m.MapLeftKey("MemberId");
            m.MapRightKey("FriendId");
            m.ToTable("MembersFriends");
        }
    );
}

надеюсь это поможет.

person Nils    schedule 23.07.2014

Вы можете заставить это работать в EF 4 CTP5, используя Model-First, но Code First CTP5 имеет слишком много ошибок с самореферентными и полиморфными конфигурациями запросов, чтобы использовать Code First для таких сценариев. Мортеза Манави (см. другой ответ) задокументировал некоторые из них в своем блоге.

person dthorpe    schedule 26.02.2011
comment
Правда что. Надеюсь, RTM выполнит наши просьбы. Code-first просто потрясающий! - person Korayem; 27.02.2011

Я хотел сделать это без необходимости писать плавный код API. Итак, вот что я думаю.

Следующий пример пытается сохранить профили других пользователей, которые посещал пользователь, и тех, кто посещал этот профиль пользователя. К сожалению, в следующем примере не поддерживаются дополнительные свойства, кроме двух идентификаторов посетителя и посещенного пользователя.

Свойства навигации были связаны с использованием тега InversePropertyAttribute.
подробнее об этом см. entityframework.net и entityframeworktutorial.net

Модель ↴

public class User
{   
    [InverseProperty(nameof(User.VisitingUsers))]
    public virtual List<User> VisitedUsers { get; set; }
    [NotMapped]
    public long? VisitedUsersCount { get { return this.VisitedUsers == null ? 0 : this.VisitedUsers.Count(); } }

    [InverseProperty(nameof(User.VisitedUsers))]
    public virtual List<User> VisitingUsers { get; set; }
    [NotMapped]
    public long? VisitingUsersCount { get { return this.VisitingUsers == null ? 0 : this.VisitingUsers.Count(); } }
}

Сгенерированный код миграции ↴

CreateTable(
    "dbo.UserUsers",
    c => new
    {
        User_Id = c.Long(nullable: false),
        User_Id1 = c.Long(nullable: false),
    })
    .PrimaryKey(t => new { t.User_Id, t.User_Id1 })
    .ForeignKey("dbo.Users", t => t.User_Id)
    .ForeignKey("dbo.Users", t => t.User_Id1)
    .Index(t => t.User_Id)
    .Index(t => t.User_Id1);
person Mina Gerges    schedule 30.06.2020
comment
Это работает даже без атрибутов InverseProperty, если есть две пользовательские коллекции. EF автоматически предполагает, что они являются копиями. - person Gert Arnold; 03.07.2020

Ваш пример - это не отношения "многие ко многим", это скорее рекурсивные отношения.

Я не знаю, как это исправить. Но проблема с вашим кодом заключается в том, что вы получите два поля в одной строке с одинаковым именем. MemberId для идентификатора строки и MemberId для идентификатора друга.

Изменить

Попробуйте сделать это так:

    class Member 
    { 
        [Key]
        public int MemberId { get; set; } 
        public string Name { get; set; }

        public virtual IList<FriendRelationship> Friends { get; set; } 

    }

    class FriendRelationship
    {
        [Key]
        public int RelationshipId { get; set; }

        public Member Friend { get; set; }
    }
person Shiraz Bhaiji    schedule 26.02.2011
comment
Для меня это может быть много ко многим, потому что это можно решить, введя таблицу [Друзья] с [LeftMemberId] и [RightMemberId]. Независимо от правильного названия, я не могу заставить это работать :( - person Korayem; 26.02.2011
comment
Спасибо, приятель, я не смог попробовать ваше решение, но это было мое первоначальное решение сделать это вручную. Не могу дождаться RTM :) - person Korayem; 27.02.2011