Свойство навигации не загружается, если заполнен только идентификатор связанного объекта - PullRequest
3 голосов
/ 26 мая 2011

Я пытаюсь установить отношения многие-к-одному. Сущность, представляющая «многие», имеет свойство навигации, указывающее на родительский объект. Это выглядит так:

public abstract class BaseEntity
{

    /// <summary>
    /// Key Field for all entities
    /// </summary>
    /// 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }


    /// <summary>
    /// Date entity was created
    /// </summary>
    public DateTime DateCreated { get; set; }

    /// <summary>
    /// Last date Modified
    /// </summary>
    public DateTime DateModified { get; set; }

    /// <summary>
    /// keep track of Row Version used for concurrency
    /// </summary>
    [Timestamp]
    public Byte[] RowVersion { get; set; }

}

public abstract class Document : BaseEntity
{
    #region Primitive Properties   


    /// <summary>
    /// Boolean value to determine if Document is in an active state
    /// </summary>
    public bool IsActive { get; set; }

    /// <summary>
    /// Document comments and information
    /// </summary>
    [Required]
    public string Description { get; set; }

    #endregion

    #region Navigation Properties

    public ICollection<Comment> Comments { get; set; }

    /// <summary>
    /// FK back to User who owns document
    /// </summary>
    //public Guid OwnerId { get; set; }

    public Guid OwnerId { get; set; }
    /// <summary>
    /// Navigation Back to User who owns document
    /// </summary>
    public User Owner { get; set; }

    #endregion
}

public class Project : BaseEntity
{
    public string Name { get; set; }
    public string ProjectNumber { get; set; }
    public string Description { get; set; }

    public string CreatedBy { get; set; }
    public string ModifiedBy { get; set; }
    public string Currency { get; set; }

    #region Navigation Properties

    public virtual Address Address { get; set; }
    public virtual CompanyCode CompanyCode { get; set; }
    public virtual ICollection<Contact> TeamMembers { get; set; }

    #endregion
}    

 public class Rfi : Document
 {
    public string Number { get; set; }

    #region Navigation Properties

    //This points back to a Project Entity
    public virtual Guid ProjectId { get; set; }
    public virtual Project Project { get; set; }

    #endregion
}

Итак, когда я вставляю вышеуказанную сущность, я передаю ProjectId из приложения в сущность Rfi (а не всю сущность Project). Все хорошо сохраняет. Проблема, с которой я сталкиваюсь, заключается в том, что когда я вытаскиваю объект Rfi из базы данных, заполняется ProjectId, но сущность Project является нулевой. Я использую Lazy Loading, по умолчанию. Нужно ли указывать свойство навигации и для объекта Project? Я не очень хочу Если я не могу выполнить сопоставление на моем Rfi для достижения этой цели.

Обновление: Я предполагал, что EF 4.1 загрузит мои объекты для меня, но иногда мне нужно явно указать, какие объекты я хочу загрузить. Я не совсем уверен, почему. Я использую репозиторий для запроса моих сущностей. Вот метод, который я использовал для запроса объекта Rfi:

    public IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate)
    {
       return _context.Set<TEntity>().AsQueryable();
    }

То, что я в итоге сделал, на моем слое Сервиса я называю так:

public Rfi FindByNumber(string number)
{
     var rfi = rfiRepository.GetQuery(r => r.Number == number).Include(r => r.Project).Single;
     return rfi
}

Ответы [ 2 ]

13 голосов
/ 27 мая 2011

Чтобы ленивая загрузка работала, вы должны настроить свои свойства навигации virtual.

Хотя это имеет смысл с точки зрения реализации, стратегия EF по игнорированию проблемы и простому возвращению null является ужасным дизайнерским решением.

С другой стороны, NHibernate по умолчанию не позволяет использовать классы, у которых не все виртуальные свойства.

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


Вы также можете попробовать явно указать свойства FK / Navigation:

public Guid ProjectId { get; set; }
[ForeignKey("ProjectId")]
public virtual Project Project { get; set; }
3 голосов
/ 23 июня 2011

Оказывается, что сопоставление, которое я создал для proeprty, создавало дублирующий идентификатор в базе данных.У меня были, например, ProjectId и Project_ID в базе данных.Я заполнял ProjectId, когда новый элемент был сохранен в контексте, но _ID не заполнялся.Это то, что EF 4.1 использует для связи данных.В моем отображении я пытался настроить проект, чтобы он не CascadeOnDelete.Вот как выглядит мое отображение:

HasOptional(rfi => rfi.Project)
    .WithOptionalDependent()
    .WillCascadeOnDelete(false);

Это отображение создавало 2 идентификатора в базе данных.Как только я удалил отображение, все работало.Мне просто нужно выяснить правильное сопоставление, чтобы я мог удалить CascadeOnDelete, сделать свойство необязательным и иметь только один идентификатор.

Я понял, что с помощью EF Power Tools .Вы можете перепроектировать вашу БД в POCO.Я изменил приведенную выше строку на:

HasOptional(r => r.Project)
    .WithMany()
    .HasForeignKey(r => r.ProjectId)
    .WillCascadeOnDelete(false);

Даже при наличии свободного интерфейса отображения немного сложно освоить.Чтобы понять, как соотносятся отношения в EF, я создал простую базу данных с моими таблицами и назначениями внешнего ключа.Затем я сначала использовал опцию Power Tools для обратного инжиниринга кода.Brilliant!

...