Entity Framework. Значение поля равно нулю после сохранения и чтения - PullRequest
0 голосов
/ 15 октября 2019

У меня проблема с EF. Могу я что-то неправильно понять ... Итак, у меня есть простая модель:

public class Image
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string ImgPath { get; set; }
}

public class UserExtendedInfo
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string UserEmail { get; set; }
    public Image Avatar { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<UserExtendedInfo>().HasRequired(r => r.AvatarPath);
}

После создания нового объекта Image, добавления его в контекст и сохранения его я вижу новую строку в таблицах Images и UserExtendedInfoes. В пользовательской таблице я вижу столбец Avatar_id с идентификатором нужной строки таблицы изображений. Но когда я пытаюсь загрузить UserExtendedInfo из базы данных - поле аватара равно нулю ....

1 Ответ

0 голосов
/ 16 октября 2019

В каркасе сущностей столбцы таблиц представлены не виртуальными свойствами. Виртуальные свойства представляют отношения между таблицами (один-ко-многим, многие-ко-многим, ...)

Теперь все зависит от того, что вы хотите: могут ли две расширенные пользовательские информации иметь одно и то же изображение аватара, и если вы измените это изображение аватара, будет ли изменено изображение или все пользователи с этим аватаром?

Если это так, между Image и UserExtendedInfo существует отношение один ко многим: все изображения используются нулем илибольше UserExtendeInfos;каждый UserExtendedInfo имеет ровно одно изображение.

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

public class Image
{
    public int Id { get; set; }          // by convention will become the primary key
    public string ImgPath { get; set; }

    // every Images is used by zero or more UserExtendedInfo (one-to-many)
    public virtual ICollection<UserExtendedInfo> UserExtendedInfos {get; set;}
}

public class UserExtendedInfo
{
    public int Id { get; set; }          // by convention will become the primary key

    public string FirstName { get; set; }
    ... // other non-virtual properties

    // Every UserExtendedInfo has exactly one Image, using foreign key
    public int AvatarId {get; set;}
    public virtual Image Avatar { get; set; }
}

Для полноты DbContext:

public class MovieDbContext : DbContext
{
    public DbSet<Image> Images {get; set;}
    public DbSet<UserExtendedInfo> UserExtendedInfos {get; set;}
}

Этого достаточно для структуры сущностей, чтобы обнаружить таблицы, столбцы в таблицахи связь между таблицами. Нет необходимости ни в аннотациях данных, ни в беглости API.

Существует небольшое отклонение от соглашений:

// Every UserExtendedInfo has exactly one Image, using foreign key
public int AvatarId {get; set;}
public virtual Image Image{ get; set; }

Если вы действительно хотите использовать Avatar в качестве свойства, возможно, выможет потребоваться свободный API в OnModelCreating:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // one-to-many relation between Image and UserExtendedInfo:
    modelBuilder.Entity<Image>()
                .HasMany(image => image.UserExtendedInfos)
                .WithRequired(userExtendedInfo => userExtendedInfo.Avatar)
                .HasForeignKey(userExtendedInfo => userExtendedInfo.AvatarId);

Приведенный выше код говорит, что каждое изображение в таблице изображений имеет ноль или более UserExtendedInfos. Доступ ко многим можно получить с помощью свойства Image.UserExtendedInfos. Каждый UserExtendedInfo принадлежит ровно одному изображению (не ноль, не два, а ровно одно: обязательно). Доступ к этому изображению осуществляется через свойство UserExtendedInfo.Avatar. Внешний ключ к изображению, к которому принадлежит UserExtendedInfo, - это UserExtendedInfo.AvatarId.

Теперь, когда вы добавляете новый UserExtendedInfo, вы не можете SaveChanges, не указав ни для внешнего ключа правильное значение, ни для Image:

var mickeyMouseImageId = myDbContext.Images
                                 .Where(image => image.Name == "Mickey Mouse)
                                 .Select(image => image.Id)
                                 .FirstOrDefault();
// TODO: check that the image really exists, so result not zero

// Add a new UserExtendedInfo that uses mickey Mouse as Avatar:
var addedUserExtendedInfo = myDbContext.UserExtendedInfos.Add(new UserExtendedInfo()
{
     // fill the foreign key:
     AvatarId = mickeyMouseId,

     ... // other properties; don't fill the primary Key in Id
});

Если вы хотите добавить новый Image и UserExtendedInfo за один шаг:

var addedUserExtendedInfo = myDbContext.UserExtendedInfos.Add(new UserExtendedInfo()
{
    // don't fill the primary key nor the foreign key, you don't know their values yet
    // add also a new Avatar
    Avatar = new Image()
    {
        // don't fill the primary key, you don't know its value yet
        ... // other Image properties

        // no need to fill the collection of Images
    },
});

Платформа Entity Framework обнаруживает, что первичные ключи равны нулю, и, таким образом, объекты добавляются в базу данных. Из-за виртуальных свойств Entity Framework знает, что внешние ключи должны быть заполнены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...