структура сущности 4.1 неверное имя столбца - PullRequest
11 голосов
/ 14 августа 2011

У меня есть два стола News и NewsComments. Я следовал правилам именования

структура NewsComments

public class NewsComment : BaseComment
{
    public int NewsId { get; set; }

    public virtual News News { get; set; }      
}

Но запрос возвращает исключение Неверное имя столбца "News_Id". Я знаю, что это исключение создало, когда в таблице не связаны столбец.

CREATE TABLE [dbo].[NewsComments](
[Id] [int] IDENTITY(1,1) NOT NULL,
[NewsId] [int] NOT NULL,
[Text] [varchar](max) NOT NULL,
[UserId] [int] NOT NULL,
[CommentDate] [datetime] NOT NULL,
[Ip] [varchar](40) NOT NULL, CONSTRAINT [PK_NewsComments] PRIMARY KEY CLUSTERED([Id] ASC )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]

BaseComment

public abstract class BaseComment : BasePersistentEntity, IComment
{

    public int UserId { get; set; }

    public virtual BaseUser User { get; set; }

    [Display(ResourceType = typeof(FrameworkResurce), Name = "CommentText")]
    public string Text { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "CommentDate")]
    public DateTime CommentDate { get; set; }


    public string Ip { get; set; }
}

Новости

public class News : BaseContent
{
    [Display(ResourceType = typeof(NewsResurce), Name = "NewsImage")]
    public string NewsImage { get; set; }

    public virtual ICollection<NewsCommentView> CommentViews { get; set; }
}

BaseContent

public abstract class BaseContent : BasePersistentEntity
{
    [Display(ResourceType = typeof(FrameworkResurce), Name = "Keywords")]
    public string Keywords { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "TitleTranslit")]
    public string TitleTranslit { get; set; }

    [Required(ErrorMessageResourceType = typeof(FrameworkResurce), ErrorMessageResourceName = "IsTextEmpty")]
    [Display(ResourceType = typeof(FrameworkResurce), Name = "Title")]
    public string Title { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "Description")]
    public string Description { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "Contents")]
    public string Contents { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "DatePublish")]
    public DateTime DatePublish { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "AuthorPublish")]
    public string AuthorPublish { get; set; }

    [Display(ResourceType = typeof(FrameworkResurce), Name = "Author")]
    public string Author { get; set; }

    [Display(ResourceType = typeof(FrameworkResurce), Name = "AuthorUrl")]
    public string AuthorUrl { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "Views")]      
    public int Views { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "Comments")]
    public int Comments { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "IsComment")]
    public bool IsComment { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "SumVote")]
    public int SumVote { get; set; }


    [Display(ResourceType = typeof(FrameworkResurce), Name = "VoteCount")]
    public int VoteCount { get; set; }

    [NotMapped]
    [Display(ResourceType = typeof(FrameworkResurce), Name = "Rating")]
    public double Rating
    {
        get
        {
            if (VoteCount > 0)
            {
                return Math.Round((float)SumVote/VoteCount, 2);
            }

            return 0;
        }
    }
}

Запрос

private IEnumerable<NewsComment> GetComments()
    {
        var news = NewsCommentRepository.AllIncluding(c=>c.User,c=>c.News);
        return news;
    }

private DataRepository<NewsComment> NewsCommentRepository
        {
            get { return DataRepository<NewsComment>.Repository; }
        }

DataRepository

public class DataRepository<T> where T : BasePersistentEntity
{
    public static DataRepository<T>  Repository
    {
        get
        {
            return new DataRepository<T>();
        }
    }

    private readonly SGNContext<T> context = new SGNContext<T>();

    public IQueryable<T> All
    {
        get { return this.context.Table; }
    }

    public IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
    {
        IQueryable<T> query = this.context.Table;
        return includeProperties.Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
    }

    public T Find(int id)
    {
        return this.context.Table.Find(id);
    }

    public void InsertOrUpdate(T country)
    {
        if (country.Id == default(int))
        {
            // New entity
            this.context.Table.Add(country);
            Save();
        }
        else
        {
            // Existing entity
            this.context.Entry(country).State = EntityState.Modified;
            Save();
        }
    }

    public void Delete(int id)
    {
        var country = this.context.Table.Find(id);
        this.context.Table.Remove(country);
        this.Save();
    }

    private void Save()
    {
        this.context.SaveChanges();
    }
}

Где используется GetComments

    [GridAction]
    public ActionResult AjaxCommentsBinding()
    {
        return View(new GridModel<NewsComment>
        {
            Data = GetComments()
        });
    }

NewsCommentViews

CREATE VIEW [dbo].[NewsCommentViews]
AS
SELECT     dbo.NewsComments.NewsId, dbo.NewsComments.Text, dbo.NewsComments.UserId, dbo.NewsComments.CommentDate, dbo.NewsComments.Ip, 
                      dbo.Roles.RoleName, dbo.Users.UserName, dbo.Users.DateRegistered, dbo.NewsComments.Id, dbo.Users.Avatar
FROM         dbo.NewsComments INNER JOIN
                      dbo.Users ON dbo.NewsComments.UserId = dbo.Users.Id INNER JOIN
                      dbo.Roles ON dbo.Users.RoleId = dbo.Roles.Id

NewsCommentViews

[Table("NewsCommentViews")]
    public class NewsCommentView : NewsComment
    {
        public string RoleName { get; set; }

        public string UserName { get; set; }

        public DateTime DateRegistered { get; set; }

        public string Avatar { get; set; }
    }

Ответы [ 2 ]

19 голосов
/ 16 августа 2011

Проблема в отношениях между News и NewsCommentView: один конец отношения - коллекция News.CommentViews. Но другой конец - , а не NewsCommentView.News, как вы, возможно, ожидаете. Зачем? Поскольку свойство News не объявлено в классе NewsCommentView, а в базовом классе NewsComment. Теперь EF не допускает, чтобы сущность участвовала в отношениях со свойством навигации, которое не объявлено в самом классе этой сущности, а только в базовом классе.

Итак, поскольку у вас нет Fluent mapping, EF определяет все отношения только по соглашениям. Что происходит?

  • News имеет объявленное свойство навигации CommentViews, указывающее на класс NewsCommentView.
  • EF не находит обратное свойство типа News, которое объявлено в классе NewsCommentView. (Есть один, но это в базовом классе, который не считается.)
  • Итак, EF предполагает, что другой конец отношения не выставлен в классе NewsCommentView.
  • Не раскрывается означает: EF не имеет ни свойства навигации, ни свойства внешнего ключа и будет предполагать, что необходимые столбцы внешнего ключа в таблице / представлении базы данных NewsCommentViews будут иметь стандартное стандартное имя.
  • Это условное название NameOfEntityClass_PKPropertyName -> News_Id

Ваше настоящее имя в представлении - NewsId. Таким образом, EF запрашивает столбец News_Id, который не существует, следовательно, исключение.

Исключение, вероятно, вызывается из-за отложенной загрузки, когда ваш MVC-View обращается к NewsComment.News.CommentViews.

Эту проблему можно решить, указав имя столбца FK явно в Fluent API (насколько я знаю, другого способа без сопоставления Fluent нет):

public class MyContext : DbContext
{
    // ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<News>()
            .HasMany(n => n.CommentViews)
            .WithRequired() // <- no param because not exposed end of relation,
                            // nc => nc.News would throw an exception
                            // because nc.News is in the base class
            .Map(a => a.MapKey("NewsId"));
    }
}

Но Внимание : Помните, что NewsCommentView.News является не другим концом отношений, принадлежащих News.CommentViews. Это означает, что если у вас есть NewsCommentView в вашей коллекции News.CommentViews, то NewsCommentView.News действительно не указывает на этот News объект. Другой конец невидим и не выставлен в модели. Приведенное выше сопоставление просто устраняет проблему с именем столбца FK, но не изменяет отношения, которые в любом случае будут создавать соглашения (за исключением, возможно, изменения отношения на обязательный вместо необязательного).

1 голос
/ 14 августа 2011

Ваш SQL не имеет подчеркивания между пользователем и идентификатором.

Обновите EDMX из базы данных (через меню правой кнопки мыши) и проверьте сопоставления.

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