Данные, связанные с EF, не сохраняются в базе данных

#c# #entity-framework #design-patterns #ef-code-first

#c# #entity-framework #шаблоны проектирования #ef-code-first

Вопрос:

Использование следующих классов по соглашению EF позволит правильно создать таблицы и ассоциации PK / FK. Однако, когда я добавляю данные в коллекцию photos и сохраняю объекты, данные в таблице Photos не сохраняются в таблице базы данных.

Я избегаю использования любых типов коллекций, которые наследуются от ICollection для общедоступного свойства, и вместо этого использовал частное резервное поле, поскольку я хочу контролировать доступ к методам добавления / удаления. Есть ли что-нибудь дополнительное, что мне нужно добавить в OnModelCreating, чтобы сообщить EF, что в IEnumerable Photos есть данные, и сохранить их?

(Данные из класса Album могут быть сохранены правильно)

 public class Album
{
    private readonly ICollection<Photo> _photos = new List<Photo>();
    public Guid Id {get; set;}      
    public string Name {get; set;}
    public virtual IEnumerable<Photo> Photos
    {
        get{ return _photos;}
    }

    public void AddPhoto(byte[] bytes, string name)
    {
        //some biz rules
        Photo p = new Photo();
        p.Bytes = bytes;
        p.Name = name;
        _photos.Add(p);
    }
}

public class Photo
{
    public Guid Id {get; set;}
    public string Name {get; set;}
    public byte[] Bytes {get; set;}
}

public class AlbumDbContext : DbContext
{
    public AlbumDbContext()
    {
        this.Database.CreateIfNotExists();
    }

    public DbSet<Album> Albums { get; set; }        


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {              
    }
}
  

Ответ №1:

Я даже удивляюсь, что таблицы и отношения созданы правильно, особенно когда ни одна из ваших сущностей не определила ключ, а контекст не определяет set для Photos . В любом случае ICollection<T> это необходимо. Ваш класс не является допустимой сущностью, и даже если вы каким-то образом заставите его работать, я ожидаю, что у вас возникнут проблемы с его использованием — например, вы можете забыть о отложенной загрузке.

Также обработка их таким образом не имеет смысла, потому что любой может преобразовать ваш enumerable обратно в collection. Вы должны создать перечислимую копию коллекции, чтобы заставить ее работать должным образом.

Единственный способ, который, возможно, может сработать, это:

 public class Album
{
    public class AlbumConfiguration : EntityTypeConfiguration<Album> 
    {
        public AlbumConfiguration()
        {
            // Inner class will see private members of the outer class
            HasMany(a => a._photos)...
        }
    }

    private readonly ICollection<Photo> _photos = new List<Photo>();
    public string Name {get; set;}
    public virtual IEnumerable<Photo> Photos
    {
        get{ return _photos;}
    }

    public void AddPhoto(byte[] bytes, string name)
    {
        //some biz rules
        Photo p = new Photo();
        p.Bytes = bytes;
        p.Name = name;
        _photos.Add(p);
    }
}
  

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

 public class AlbumDbContext : DbContext
{
    public DbSet<Album> Albums { get; set; }        
    public DbSet<Photo> Photos { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {    
        modelBuilder.Configurations.Add(new Album.AlbumConfiguration());          
    }
}
  

Это решение довольно уродливое, потому что оно делает вашу сущность зависимой от entity framework.

Комментарии:

1. Да, у фактического кода есть свойства идентификатора. Просто обновил код для полноты.

2. Можете ли вы объяснить немного больше о преобразовании перечисляемого обратно в коллекцию? Как это возможно? Единственный способ добавить фотографии — это использовать метод AddPhoto. У клиента не должно быть способа изменить коллекцию …?

3. Вы можете просто вызвать (List<Photo>)album.Photos

4. Спасибо, что указали на это. Понятия не имел, что это возможно! Как можно было бы защитить коллекцию?

5. @Diego — Мы хорошо защищаем от клиентов, использующих API. Они просто не могут просто добавлять объекты без действующих бизнес-правил. Я понимаю, что возврат только для чтения в получателе может ограничить доступ?