我一直在研究一个类似Dropbox的简单应用程序,以学习一些ASP.NET MVC。但即使在让页面正常工作之前,我已经卡住了,而且那里有太多的信息,我再也看不到树林了。
我的情况:
我想在页面上显示属于某个人的某个文件夹中的所有文件。我事先设计了我的数据库,然后从中生成了Code First EF模型。数据库的相关部分如下。请注意,AspNetUsers
是MVC5身份的一部分。将Identity
链接到我自己的表似乎是最困难的部分,因为属于Identity
的表是在IdentityModels中实现的,而我的表是在TADModel中实现的。
我一直在关注this page的各种教程,但似乎无法找到任何可以帮助我完成我需要的东西。我基本上只是尝试执行以下查询:
SELECT f.FileName, f.FileSize
FROM Files f
INNER JOIN FileTree ft ON ft.FolderID = f.FolderID
INNER JOIN AspNetUsers u ON ft.UserID = u.Id
WHERE u.id = @id AND ft.FolderPath = @path;
根据前面提到的一个教程,我应该能够做一些事情:
namespace TAD.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("FileTree")]
public partial class FileTree
{
[Key]
public string FolderID { get; set; }
[Required]
[StringLength(128)]
public string UserID { get; set; }
[Required]
[StringLength(255)]
public string FolderName { get; set; }
[Required]
[StringLength(255)]
public string FolderPath { get; set; }
public virtual ICollection<File> Files { get; set; }
public virtual ApplicationUser user { get; set; }
}
}
Files Collection应该找到与路径关联的文件,用户应该找到与路径关联的用户。但在脚手架期间,我遇到了TAD.Models.IdentityUserRole: EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType'
的错误。由于ApplicationUSer user
这个问题对我来说似乎很混乱。我根本不知道我在找什么。我提到的教程目前的情况对我的需求来说太简单了,而其他信息则太先进了。
编辑:这是文件模型:
namespace TAD.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class File
{
[Key]
public string FileID { get; set; }
[Required]
[StringLength(128)]
public string UserID { get; set; }
[Required]
[StringLength(128)]
public string FolderID { get; set; }
[Required]
[StringLength(255)]
public string FileName { get; set; }
public decimal FileSize { get; set; }
public bool IsPublic { get; set; }
public virtual ApplicationUser user { get; set; }
public virtual FileTree folder { get; set; }
}
}
答案 0 :(得分:2)
你并不孤单。数据建模掩盖了很多事情,因此弄清楚什么是对错是很棘手的。
使用LINQ内部联接并没有什么问题,因为它可以工作,它可以满足您的需求。
然而,将ICollection添加到FileTree的数据模型中描述了在阅读代码时可以观察到的永久关系,并且在您感觉到这种情况时可以使用(这可能是经常的,因为它们之间的联系非常密切) 。即它不仅提供与连接相同的功能,而且还解释了与其他程序员的关系,无需注释或阅读代码示例。
要使用这些关系,大多数对象关系映射(实体框架和NHibernate是ORM的两个示例)要求模型指定主键,以便它们在集合中的子表之间挂接外键以及包含该集合的父表。
所以,长话短说,请使用ICollection,但是也要在模型上为File指定主键。
答案 1 :(得分:0)
为什么你想加入AspNetUsers
你没有从AspNetUsers
中选择任何只是额外加入的数据。
你只需要这个
SELECT f.FileName, f.FileSize
FROM Files f
INNER JOIN FileTree ft ON ft.FolderID = f.FolderID
WHERE ft.UserID = @id AND ft.FolderPath = @path;
您的EF LINQ查询将类似于'
var results = (from F in Files
join FT in FileTree on F.FolderID equals FT.FolderID
where FT.UserID == "Your User ID" && FT.FolderPath == "SomePath"
Select new { F.FileName, F.FileSize}).ToList();
答案 2 :(得分:0)
对于Identity Stuff,你可以这样做:
using System;
using Microsoft.AspNet.Identity.EntityFramework;
/// <summary>
/// The guid role.
/// </summary>
public class GuidRole : IdentityRole<Guid, GuidUserRole>
{
/// <summary>
/// Initializes a new instance of the <see cref="GuidRole"/> class.
/// </summary>
public GuidRole()
{
this.Id = Guid.NewGuid();
}
/// <summary>
/// Initializes a new instance of the <see cref="GuidRole"/> class.
/// </summary>
/// <param name="name">
/// The name.
/// </param>
public GuidRole(string name)
: this()
{
this.Name = name;
}
}
public class GuidUserRole : IdentityUserRole<Guid> { }
public class GuidUserClaim : IdentityUserClaim<Guid> { }
public class GuidUserLogin : IdentityUserLogin<Guid> { }
/// <summary>
/// The user.
/// </summary>
public class User : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>
{
public User()
{
this.Id = Guid.NewGuid();
}
/// <summary>
/// Gets or sets the first name.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Gets or sets the last name.
/// </summary>
public string LastName { get; set; }
}
所以在这里你可以看到我已经让我的所有身份模型都有Guid
作为主键类型。您可以轻松地将其更改为int
,我认为这是要走的路!
如果你必须做复杂的连接,你应该将EF留在其中,因为它只是一个ORM。它无法取代SQL。但是,您可以在代码中创建一个可爱的SQL连接,并让EF执行该查询!
using (var context = new ApplicationDbContext())
{
var result = context.Database.SqlQuery<SomeDtoToHoldTheData>(
"SOME LOVELY SQL" +
"SELECT * FROM DATABASE TABLE" +
"EVEN PARAMS GO @HERE",
new SqlParameter("Here", "My Param"));
}
所以我建议先看看这个?
显然不要将字符串与+
连接起来,它们是不可变的。
让我们进行查询:
public class FileResultDto
{
public string FileName {get;set;}
public decimal FileSize {get;set;}
}
var query = "SELECT f.FileName, f.FileSize" +
"FROM Files f" +
"INNER JOIN FileTree ft ON ft.FolderID = f.FolderID" +
"INNER JOIN AspNetUsers u ON ft.UserID = u.Id" +
"WHERE u.id = @id AND ft.FolderPath = @path;";
var userIdParam = new SqlParameter("id", userId);
var pathParam = new SqlParameter("path", path);
var result = context.Database.SqlQuery<FileResultDto>(query, userIdParam, pathParam);
如果你不想这样走。 LINQ我猜想可能是这样的:
var fileTrees = context.FileTrees.Where(f => f.FolderPath == folderPath && f.UserID == userId)
.GroupJoin(
context.Files
ft => ft.FolderID,
f => f.FolderID,
(fileTree, files) => { fileTree, files });
var users = context.Users.FirstOrDefault(u => u.Id == userId);
因此,fileTrees
是一个包含FileTree
实体和File
实体列表的匿名对象列表。基于你当前的模型。
答案 3 :(得分:0)
虽然添加View不会在视图模板中选择Context DB类来修复&#34;实体类型没有键定义错误&#34;。
如需进一步参考,请访问:https://www.youtube.com/watch?v=T2R8tA80ZuE **