Может кто-нибудь сказать мне, как я могу исправить свою модель (используя FluentAPI), чтобы я мог назначить другого пользователя для моей User.FriendCollection? - PullRequest
2 голосов
/ 15 марта 2012

Я новичок в CodeFirst и пытаюсь создать коллекцию друзей, чтобы два пользователя могли видеть друг друга в своей коллекции друзей.

Вот мой класс пользователя:

public class User
{
    public User()
    {
        if (FriendCollection == null) FriendCollection = new Collection<Friend>();
    }
    public long ID { get; set; }
    public virtual ICollection<Friend> FriendCollection { get; set; }
}

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        HasKey(x => x.ID);
    }
}

Вот мой класс друга:

public class Friend
{
    public Friend()
    {
        DateAdded = DateTime.UtcNow;
    }
    public long ID { get; set; }
    public DateTime DateAdded { get; set; }
    public long UserID { get; set; }
    public virtual User User { get; set; }
}

public class FriendConfiguration : EntityTypeConfiguration<Friend>
{
    public FriendConfiguration()
    {
        HasKey(x => x.ID);
        HasRequired(x => x.User).WithMany(x => x.FriendCollection).HasForeignKey(x => x.UserID);
    }
}

Вот мой класс сущности:

    public Entities()
    {
        Database.SetInitializer<Entities>(new DropCreateDatabaseAlways<Entities>());
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Friend> Friends { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UserConfiguration());
        modelBuilder.Configurations.Add(new FriendConfiguration());

        base.OnModelCreating(modelBuilder);
    }
}

А вот мой код консоли и в идеале то, чего я хотел бы достичь:

        using (Entities db = new Entities ())
        {
            var u1 = new User();
            db.Users.Add(u1);

            var u2 = new User();
            db.Users.Add(u2);

            u1.FriendCollection.Add(new Friend { User = u2 });
            u2.FriendCollection.Add(new Friend { User = u1 });

            try
            {
                var cnt = db.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                    }
                }
            }

SaveChanges выдает ошибку всякий раз, когда я пытался заполнить класс Friend объектом User, говоря:

Нарушено ограничение множественности.Роль "Friend_User_Target" отношения "Entities.Friend_User" имеет кратность 1 или 0..1.

Если я назначу идентификатор пользователя следующим образом:

u1.FriendCollection.Add (new Friend {UserID = u2.ID});

Это позволяет мне сохранять сущности, но не правильно!

Когда я перешагиваю код, я могу изолировать проблему и вот что я нахожу:

b.FriendCollection.Add(new Friend { UserID = a.ID });
//Friend.UserID = 1
db.SaveChanges();
//Friend.UserID = 2 matching the b.ID

Так что теперь я могу вернуться к моему предыдущему примеру и SaveChanges (), не выдавая ошибку, если я назначуДруг. Пользователь для вызывающего пользователя.Например:

b.FriendCollection.Add(new Friend { User = b }); 
db.SaveChanges()

Но когда я пытаюсь назначить другого пользователя, я получаю сообщение об ошибке.Например:

b.FriendCollection.Add(new Friend { User = a }); 
db.SaveChanges()

Я получаю:

Нарушено ограничение множественности.Роль Friend_User_Target отношения Entities.Friend_User имеет кратность 1 или 0..1.

Может кто-нибудь рассказать, как я могу исправить свою модель (используя FluentAPI), чтобыЯ могу назначить другого пользователя для моей User.FriendCollection?

1 Ответ

0 голосов
/ 15 марта 2012

Неверное отображение, по крайней мере, неверное значение отношений в вашей модели.

Ваше сопоставление создает одно единственное отношение, и два навигационных свойства User.FriendCollection и Friend.User являются двумя концами этого единственного отношения. Вы определили их как обратные свойства.

Но это будет означать, что если у вас есть пользователь UserA, у которого есть FriendB в FriendCollection, то User в FriendB должен быть UserA, а не любым другим пользователем. Ваша модель может выразить только то, что пользователь является, так сказать, другом. Поскольку вы добавляете в коллекцию другого пользователя, вы получаете исключения.

По моему мнению, сущность Friend не представляет друга = другого пользователя, но на самом деле она выражает отношения. Это своего рода промежуточный объект для отношений «многие ко многим» между пользователями, и это отношение Friendship (я бы предпочел назвать это так).

В любом случае ваша модель нуждается в двух отношениях. Вы можете оставить объекты такими, какие они есть, но использовать это отображение:

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        HasKey(x => x.ID);
        HasMany(x => x.FriendCollection)
            .WithRequired();
    }
}

public class FriendConfiguration : EntityTypeConfiguration<Friend>
{
    public FriendConfiguration()
    {
        HasKey(x => x.ID);
        HasRequired(x => x.User)
            .WithMany()
            .HasForeignKey(x => x.UserID)
            .WillCascadeOnDelete(false);
    }
}

(Отключение каскадного удаления в одном из отношений необходимо, чтобы избежать печально известного «исключения каскадного удаления нескольких файлов».)

Обратите внимание, что теперь у вас есть два внешних ключа в таблице Friend, UserID для второго и User_ID для первого сопоставления. Вы можете переименовать имя столбца по умолчанию, добавив Map(m => m.MapKey("SomeUserID")) к первому сопоставлению.

С этим отображением ваш консольный код должен работать.

...