C# 卷影属性以访问具有表/层次结构继承模型的相关实体
我正在用ASP.NETCore为一个网站构建一个菜单系统。让我们假设我有两个数据库表,一个用于C# 卷影属性以访问具有表/层次结构继承模型的相关实体,c#,linq,asp.net-core-mvc,entity-framework-core,navigation-properties,C#,Linq,Asp.net Core Mvc,Entity Framework Core,Navigation Properties,我正在用ASP.NETCore为一个网站构建一个菜单系统。让我们假设我有两个数据库表,一个用于页面,一个用于文章,尽管它们是不同的实体才是真正重要的。它们都有一个名称和永久链接属性 在我的菜单中(我也希望存储在数据库中),我希望引用每个实体的名称和永久链接。我设计了一个简单的菜单类/模型结构,如下所示: 抽象菜单项 public abstract class MenuItem { [Key] public int MenuItemId { get; set; } publ
页面
,一个用于文章
,尽管它们是不同的实体才是真正重要的。它们都有一个名称
和永久链接
属性
在我的菜单中(我也希望存储在数据库中),我希望引用每个实体的名称
和永久链接
。我设计了一个简单的菜单类/模型结构,如下所示:
抽象菜单项
public abstract class MenuItem
{
[Key]
public int MenuItemId { get; set; }
public int MenuPosition { get; set; }
public abstract string Name { get; }
public abstract string Permalink { get; }
}
public class ArticleMenuItem : MenuItem
{
public ArticleMenuItem() {}
public ArticleMenuItem(Article article)
{
Article = article;
}
public string Name => Article.Name;
public string Permalink => Article.Permalink;
[Required]
public int ArticleId { get; set; }
[ForeignKey("ArticleId")]
public Article Article { get; set; }
}
public class PageMenuItem : MenuItem
{
public PageMenuItem() {}
public PageMenuItem(Page page)
{
Page = page;
}
public string Name => Page.Name;
public string Permalink => Page.Permalink;
[Required]
public int PageId { get; set; }
[ForeignKey("PageId")]
public Page Page{ get; set; }
}
具体文章菜单项
public abstract class MenuItem
{
[Key]
public int MenuItemId { get; set; }
public int MenuPosition { get; set; }
public abstract string Name { get; }
public abstract string Permalink { get; }
}
public class ArticleMenuItem : MenuItem
{
public ArticleMenuItem() {}
public ArticleMenuItem(Article article)
{
Article = article;
}
public string Name => Article.Name;
public string Permalink => Article.Permalink;
[Required]
public int ArticleId { get; set; }
[ForeignKey("ArticleId")]
public Article Article { get; set; }
}
public class PageMenuItem : MenuItem
{
public PageMenuItem() {}
public PageMenuItem(Page page)
{
Page = page;
}
public string Name => Page.Name;
public string Permalink => Page.Permalink;
[Required]
public int PageId { get; set; }
[ForeignKey("PageId")]
public Page Page{ get; set; }
}
具体页面菜单项
public abstract class MenuItem
{
[Key]
public int MenuItemId { get; set; }
public int MenuPosition { get; set; }
public abstract string Name { get; }
public abstract string Permalink { get; }
}
public class ArticleMenuItem : MenuItem
{
public ArticleMenuItem() {}
public ArticleMenuItem(Article article)
{
Article = article;
}
public string Name => Article.Name;
public string Permalink => Article.Permalink;
[Required]
public int ArticleId { get; set; }
[ForeignKey("ArticleId")]
public Article Article { get; set; }
}
public class PageMenuItem : MenuItem
{
public PageMenuItem() {}
public PageMenuItem(Page page)
{
Page = page;
}
public string Name => Page.Name;
public string Permalink => Page.Permalink;
[Required]
public int PageId { get; set; }
[ForeignKey("PageId")]
public Page Page{ get; set; }
}
然后,我为相关的DbContext
覆盖onModelCreating(ModelBuilder-ModelBuilder)
,因为我不想使单个DbSet的
可用:
modelBuilder.Entity<PageMenuItem>();
modelBuilder.Entity<ArticleMenuItem>();
不幸的是,这导致了一个空对象异常
,然后我记得EF Core不支持延迟加载。因此,当我在存储库中获得菜单项时,我想急切地加载阴影属性,特别是相关的实体
访问阴影属性有多种方法。我采用的第一种更新存储库方法如下所示:
public IEnumerable<MenuItem> GetAllMenuItems() => _context.MenuItems
.Include(item => context.Entry(item).Property("Page").CurrentValue)
.Include(item => context.Entry(item).Property("Article").CurrentValue)
public IEnumerable<MenuItem> GetAllMenuItems()
{
var menuItems = _context.MenuItems.ToList();
_context.MenuItems.OfType<ArticleMenuItem>().Include(e => e.Article).Load();
_context.MenuItems.OfType<PageMenuItem>().Include(e => e.Page).Load();
return menuItems;
}
结果:
InvalidOperationException:属性表达式'item=>property(item,“Page”)'无效。表达式应表示属性访问:“t=>t.MyProperty”
我想知道是否可以在继承模型中使用阴影属性进行导航?如果是,我如何包括相关实体,以便在我的具体
MenuItem
类中可以访问它?e、 g.对于publicstringname=>Page.Name
不幸的是,目前没有用于快速加载派生类属性的语法(请注意,它们与影子属性不同)。这加上缺少延迟加载,使得显式加载成为唯一的选择。例如,查看如何将其用于单个项目,对于项目集合,恐怕您必须将结果具体化为一个列表,然后使用具体类型的显式加载并依赖EF导航属性修复
例如,它可以是这样的:
public IEnumerable<MenuItem> GetAllMenuItems() => _context.MenuItems
.Include(item => context.Entry(item).Property("Page").CurrentValue)
.Include(item => context.Entry(item).Property("Article").CurrentValue)
public IEnumerable<MenuItem> GetAllMenuItems()
{
var menuItems = _context.MenuItems.ToList();
_context.MenuItems.OfType<ArticleMenuItem>().Include(e => e.Article).Load();
_context.MenuItems.OfType<PageMenuItem>().Include(e => e.Page).Load();
return menuItems;
}
public IEnumerable GetAllMenuItems()
{
var menuItems=_context.menuItems.ToList();
_context.MenuItems.OfType().Include(e=>e.Article.Load();
_context.MenuItems.OfType().Include(e=>e.Page.Load();
返回菜单项;
}
另一种解决方法(我是否说过只有一种)是使用手动联合查询,这基本上扼杀了TPH的想法:
public IEnumerable<MenuItem> GetAllMenuItems() =>
_context.MenuItems.OfType<ArticleMenuItem>().Include(e => e.Article)
.AsEnumerable() // to avoid runtime exception (EF Core bug)
.Concat<MenuItem>(
_context.MenuItems.OfType<PageMenuItem>().Include(e => e.Page));
public IEnumerable GetAllMenuItems()=>
_context.MenuItems.OfType().Include(e=>e.Article)
.AsEnumerable()//避免运行时异常(EF核心错误)
康卡特先生(
_context.MenuItems.OfType().Include(e=>e.Page));
好的,我对术语的误解。这有助于我了解一开始出了什么问题。我来看看你的建议。