实体框架 - ICollection 属性始终为空 - getter setter 问题



我有一个使用.netcore identity' . I have a classApplicationUser'(又名所有者)的.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

相关内容

  • 没有找到相关文章