我有一个使用.netcore identity' .
I have a class
ApplicationUser'(又名所有者)的.net core 2.0
项目,3
其他类的媒体对象Videos, Images, and Audio ("Clips")
。到目前为止,一切都很好。我碰壁的地方是当我尝试重构时,这样就不必碰到数据库并说这样的话:
user=_usermanager.getuserasync(User)
images= _context.Images.Where(i=>i.i.Owner.username== user.username)
我希望能够通过简单地说来访问同样的东西
user.images
希望允许我说这样的话:'foreach (User.Clips中的音频剪辑){//do the hokeypokee//}
因此,我修改了ApplicationUser
类,为每个媒体类包含一个ICollection<Type>
。无论我做什么,但是当我访问user.images
等时,我总是得到空。(也尝试了虚拟导航道具)
而不是坐在这里解释我认为它是什么(也许我没有对getter和setter做什么?)这会令人困惑,我想我只是让你们告诉我什么方向,我应该进去,因为我已经进入了很多兔子洞现在试图弄清楚这一点。实体框架似乎井井有条,它只是我没有做的事情......我什至无法弄清楚(如果不是在 EF 的某个地方)setter 最初是如何定义的,这意味着它如何知道哪些图像属于用户,而无需查询数据库以查看哪些图像具有 FK 那么多用户......无论如何,我打得越多,我就越困惑自己,哈哈。
用户类:
public class ApplicationUser : IdentityUser, ITraits
{
public int Age { get; set; }
public Ethnicity Ethnicity { get; set; }
public Color EyeColor { get; set; }
public Color HairColor { get; set; }
public int Height { get; set; }
public Race Race { get; set; }
public CuckRole CuckRole { get; set; }
public BiologicalSex BiologicalSex { get; set; }
public Sexuality Sexuality { get; set; }
public Color SkinColor { get; set; }
public int Weight { get; set; }
public DateTime BirthDay { get; set; }
public ICollection<Image> Images { get; set; }
public ICollection<Audio> Clips { get; set; }
public ICollection<Video> Videos { get; set; }
public bool Equals(Traits other) => throw new NotImplementedException();
}
然后是我的媒体课(只有一个相同的只是不同的名字)
public class Audio
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public ApplicationUser Owner { get; set; }
//Constructors//
public Audio()
{
}
public Audio(string path,ApplicationUser owner)
{
Path = path;
Owner = owner;
}
}
编辑
好的,所以我尝试尽我所能实现建议的代码,到目前为止,这就是我想出的:
媒体类 :
public class Audio
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public ApplicationUser Owner { get; set; }
public string OwnerId { get; set; }
//Constructors//
public Audio()
{
}
public Audio(string path,ApplicationUser owner)
{
Path = path;
Owner = owner;
}
}
我的应用程序用户类现在看起来像这样:
public class ApplicationUser : IdentityUser, ITraits
{
public int Age { get; set; }
public Ethnicity Ethnicity { get; set; }
public Color EyeColor { get; set; }
public Color HairColor { get; set; }
public int Height { get; set; }
public Race Race { get; set; }
public CuckRole CuckRole { get; set; }
public BiologicalSex BiologicalSex { get; set; }
public Sexuality Sexuality { get; set; }
public Color SkinColor { get; set; }
public int Weight { get; set; }
public DateTime BirthDay { get; set; }
public ICollection<Image> Images { get; set; }
public ICollection<Audio> Clips { get; set; }
public ICollection<Video> Videos { get; set; }
public bool Equals(Traits other) => throw new NotImplementedException();
}
最后是我的DBContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Cucklist.Models.Image> Images { get; set; }
public DbSet<Cucklist.Models.Video> Videos { get; set; }
public DbSet<Cucklist.Models.Audio> Clips { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Image>().ToTable("Image")
.HasOne(Image => Image.Owner)
.WithMany(Owner => Owner.Images)
.HasForeignKey(Image => Image.OwnerId);
builder.Entity<Video>().ToTable("Video")
.HasOne(Video => Video.Owner)
.WithMany(Owner => Owner.Videos)
.HasForeignKey(Video =>Video.OwnerId );
builder.Entity<Audio>().ToTable("Clips")
.HasOne(Audio => Audio.Owner)
.WithMany(Owner => Owner.Clips)
.HasForeignKey(Audio =>Audio.OwnerId );
}
}
可悲的是,我在访问User.media(图像,视频等)时仍然得到一个空
值嘿伙计们再次感谢您的帮助(@nilsK) - 所以答案最终是一个实体框架"东西"。
基本上,实体框架核心不支持延迟加载,直到现在处于预览状态的 v2.1(不确定我是否错过了确保指定它是实体框架核心,但我猜这一切都假设,因为它是一个 .net 核心项目,您必须使用 Ef Core 对于 .net 核心项目。 无论如何,即使 Microsoft.EntityFrameworkCore 更新并安装了 2.1.0-previewfinal-2,它仍然不起作用。
换句话说,为了使其"工作" 换句话说 - 在尝试访问相关实体时不拉回空值,您还必须安装软件包Microsoft.EntityFramworkCore.Proxies。
实际上,这是在ef core中"启用"延迟加载的最简单方法(根据MS);使用代理。尽管还有另外两种方法可用,但实现起来要复杂得多
这是最终一劳永逸地回答这个问题的文章的链接: https://learn.microsoft.com/en-us/ef/core/querying/related-data
所以短而瘦是一旦你安装了你必须(应该为上面的选项)进行所有调用。在 DI 容器中使用 LazyLoadProxies() 选项 -- 转到启动.cs并修改 DBContext 选项添加 .在 .UseSqlServer(...),仅此而已....
现在,当您使用相关实体实例化实体时,它们将在首次访问属性时加载......所以基本上它将停止返回空值!!
否则,您将不得不使用隐式包含语句等... 预先加载不是和选项,而是每个查询声明......
总结:
步骤 1:安装 Microsoft.EntityFrameworkCore 预览版 2.1.xx 第 2 步:安装 Microsoft.EntityFrameworkCore.Proxies 步骤 3:修改服务容器/启动.cs(配置服务)DBContext 以包含选项 .使用LasyLoad代理 所以你的旧代码可能看起来像: 服务业。AddDbContext(options =>
服务业。AddDbContext(options =>options.UseSqlServer(Configuration.GetConnectionString("LocalConnection"))
现在它可能看起来像这样:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("LocalConnection"))
.UseLazyLoadingProxies());
步骤4 - 修改DBContext类以轻松加载相关实体(是的,它们必须全部列出,这可能不是最佳的,但我相信MS会解决这个问题)
builder.Entity<Image>().HasOne(u => u.ApplicationUser)
.WithMany(i => i.Images)
.HasForeignKey(u => u.ApplicationUserId)
.HasConstraintName
(
"FK_Image_AspNetUsers_ApplicationUserId"
);
builder.Entity<Video>().HasOne(u => u.ApplicationUser)
.WithMany(p => p.Videos)
.HasForeignKey(u => u.ApplicationUserId)
.HasConstraintName
(
"FK_Video_AspNetUsers_ApplicationUserId"
);
builder.Entity<Audio>().HasOne(u => u.ApplicationUser)
.WithMany(p => p.Audios)
.HasForeignKey(u => u.ApplicationUserId)
.HasConstraintName
(
"FK_Audio_AspNetUsers_ApplicationUserId"
);
您会注意到im使用身份核心 - 在"AspNetUsers"表中没有ApplicationUserId列,因此您必须具有外键约束,如果您适当地修改了类,该约束应该已经存在,我将在下面显示: 第 5 步 确保你的课程看起来像这样 -->
应用程序用户类
public class ApplicationUser : IdentityUser, ITraits
{
public int Age { get; set; }
public Ethnicity Ethnicity { get; set; }
public Color EyeColor { get; set; }
public Color HairColor { get; set; }
public int Height { get; set; }
public Race Race { get; set; }
public CuckRole CuckRole { get; set; }
public BiologicalSex BiologicalSex { get; set; }
public Sexuality Sexuality { get; set; }
public Color SkinColor { get; set; }
public int Weight { get; set; }
public DateTime BirthDay { get; set; }
public virtual ICollection<Image> Images { get; set; }<--must be virtual
public virtual ICollection<Video> Videos { get; set; }<--must be virtual
public virtual ICollection<Audio> Audios { get; set; }<--must be virtual
public bool Equals(Traits other)
{
throw new NotImplementedException();
}
}
媒体类之一:
图像:
public class Image
{
//Fields and Properties//
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }<-be virtual
public virtual string ApplicationUserId { get; set; }<--must be virtual
public Image()
{
}
public Image(string path) => Path = path;
}
步骤 6 在视图中,您需要做的就是拥有一个应用程序用户,您可以使用 httpcontext 拉取当前用户,如下所示:
最好在控制器中执行此操作,尽管您可以在视图中执行此操作
应用程序用户用户 = 等待_usermanager。GetUserAsync(HttpContext.User);
然后将用户传递给视图
返回视图(用户)
步骤 7
在您看来,使用户模型是应用程序用户
在您的视图中的某个地方尝试通过用户对象访问媒体类,以便
foreach (Audio clip in Model.Clips)
{
<img src="@clip.path" />
}
中提琴!
**编辑有关主题和代理等的有用阅读 - ef core 2-1 延迟加载的新功能
在 DbContext 类中,您可以覆盖 OnModelCreate 方法并在此处配置关系。 有一些更清洁的方法,但这可能是一个好的开始。
protected override void OnModelCreationg(DbModelBuilder modelBuilder)
{
// on-to-many relation example
modelBuilder.Entity<Audio>()
.HasOptional(audio => audio.Owner)
.WithMany(owner => owner.Clips)
.HasForeignKey(audio => audio.OwnerId) // this one is missing in your example
.WillCascadeOnDelete(false); // maybe true? depending on what should happen if the user gets deleted
}
你需要告诉 EF 如何管理你的关系 - 你将需要一个外键 (Audio.OwnerId)。
进一步调查的另一个关键词可能是ObjectEntityConfiguration
。