2014-11-10 3 views
3

저는 간단한 Dropbox와 유사한 응용 프로그램에서 ASP.NET MVC에 대해 배우고 있습니다. 그러나 페이지가 잘 돌아가기 전에도 나는 꼼짝 못하게되었습니다. 거기에는 너무 많은 정보가있어 나무에 대한 숲을 더 이상 볼 수 없습니다.ASP.NET MVC에서 두 테이블을 결합하는 적절한 방법은 무엇입니까?

내 상황 :

내가 한 페이지에 어떤 사람에 속하는 특정 폴더에있는 모든 파일을 표시 할

. 나는 데이터베이스를 미리 설계하고 그로부터 Code First EF 모델을 생성했다. 데이터베이스의 관련 부분은 다음과 같습니다. AspNetUsers은 MVC5 ID의 일부입니다. 내 테이블이 TADModels에서 구현되는 동안 Identity이 내 자신의 테이블에 연결하는 것이 가장 어려운 부분 인 것 같습니다.

enter image description here

나는 this page에 다양한 자습서를 다음 봤는데,하지만 제가 필요 달성하는 데 도움이 아무것도 찾을 수없는 것.

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; } 
    } 
} 

: 상기 자습서 중 하나에 따르면

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; 

이, 내가의 라인을 따라 뭔가를 할 수 있어야 해요 : 나는 기본적으로 그냥 다음 쿼리를 실행하기 위해 노력하고있어 파일 콜렉션은 경로와 연관된 파일을 찾고 사용자는 경로와 연관된 사용자를 찾는다. 그러나 스캐 폴딩 중에는 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

무엇 당신의'File' 모델은 어떻게 구성 되나요? LINQ – beautifulcoder

+0

@beautifulcoder를 통해 수동으로 수행 할 수 있습니다. 내 File 클래스가 추가되었습니다. Key annotation은 아래 답변 중 하나에서 제안되었으며 실제로 필요한지 전혀 알 수 없습니다. –

+0

아이덴티티 모델을 쉽게 상속 받아 자신의 속성을 추가 할 수 있습니다! 이것은 다소 도움이 될 수 있습니다 :'public class MyUser : IdentityUser {}' –

답변

2

당신은 혼자가 아니에요 :이 파일 모델이다. 데이터 모델링은 옳고 그름을 파악하기가 까다로울 수 있다는 점에서 너무 많은 가면을가립니다.

LINQ 내부 조인을 사용하면 문제가되지 않으며 필요한만큼 얻을 수 있습니다.

그러나 FileTree의 데이터 모델에 ICollection을 추가하면 코드를 읽을 때 관찰 할 수있는 영구적 인 관계가 묘사되며 사용자가 느끼기를 원할 때마다 사용됩니다. 즉, 조인과 동일한 기능을 제공 할뿐만 아니라 주석이나 코드 샘플을 읽지 않고도 다른 프로그래머와의 관계를 설명합니다.

이러한 종류의 관계를 사용하려면 대부분의 개체 관계형 매핑 (Entity Framework 및 ORM의 두 가지 예가되는 NHibernate)에서는 모델에서 기본 키를 지정해야만 모델의 기본 키가 지정되므로 하위 키와 하위 키 사이에 외래 키를 연결해야합니다. 컬렉션 및 컬렉션이있는 상위 테이블

짧게 이야기하면 ICollection을 사용하지만 파일에 대한 모델의 기본 키도 지정하십시오.

+0

File에 [Key] 주석을 추가했지만 도움이되지 않습니다. 그리고 튜토리얼을 통해 알 수 있듯이 MVC는 FileID라는 이름을 가진 내 키가 무엇인지 알고 있어야합니다. 이 주석을 Identity 클래스에 추가해야 할 수도 있습니다. –

+0

죄송합니다. 예, 그렇게해야합니다. 왜 그런지 궁금하다면, 대부분의 ORM은 반복적으로 데이터베이스에 충돌하는 것을 방지하기 위해 일정 수준의 객체 캐싱을 구현하기 때문입니다. 객체가 이미로드되었는지 여부를 합리적으로 확인할 수있는 유일한 방법은 Key를 사용하여 객체를 검사하는 것입니다. –

0

왜 가입 하시겠습니까? AspNetUsers에서 추가 데이터에 속하는 데이터를 선택하지 않으 셨습니다.그래서

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; } 
} 

:

당신은 당신이 할 수있는 신원 물건

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(); 
+0

요점은 내 SQL 쿼리가 아니 었습니다. 이것은 내가 성취하고자하는 것의 예일뿐입니다. 나는 단지 내 페이지를 작동시키는 위치를 지정해야하는 코드를 모른다. 당신의 제안은 효과가 있을지 모르지만, 다른 곳에서 실수로 인해 비계를 세울 수는 없습니다. –

+0

IdentityUserRole을 수정 했습니까? 기본 양식 ASPNET id로 키를 가져야하며 스캐 폴딩 중에 모델에 대한 뷰를 생성 할 때를 의미합니까? 그렇다면 어떤 모델을 뷰에 바인딩하려합니까? – HaBo

+0

Identity와 관련된 내용을 수정하지 않았습니다.내 프로젝트에는이 모델의 구현이 있지만 샘플 프로젝트 (새 프로젝트를 만들 때마다 생성됨)에 의해 생성되었습니다. 스캐 폴딩은 컨트롤러> 추가> 새 스캐 폴딩 된 아이템을 마우스 오른쪽 버튼으로 클릭하는 것입니다. 이것은 컨트롤러와 뷰를 생성합니다. 내가 바인딩하려고하는 모델은 FileTree이며 File 및 IdentityUser에 대한 링크가 있습니다. –

0

'와 같은 그냥

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 쿼리 할 수 ​​것입니다 뭔가가 필요 여기서 모든 아이덴티티 모델에 기본 키 유형이 Guid임을 알 수 있습니다. 당신은 쉽게 그것을 int으로 바꿀 수 있습니다, 그리고 나는 그것이 갈 길이라고 생각합니다!

복잡한 조인을해야하는 경우 단순히 ORM이기 때문에 EF를 그대로 두어야합니다. 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); 

이 길을 갈하지 않으려면. fileTrees에 따라서

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); 

FileTree 개체와 File 기관의 목록을 들고 익명 객체의 목록입니다

: 나는 추측 것 LINQ는 다음과 같이 갈 수있다. 현재 모델을 기반으로합니다.

0

보기를 추가하는 동안보기 템플리트에서 "엔티티 유형에 키 정의 오류가 없음"을 수정하는 컨텍스트 DB 클래스를 선택하지 마십시오. 더 참고로

방문하십시오 : https://www.youtube.com/watch?v=T2R8tA80ZuE **

+0

이것은 답변이 아닙니다! –

관련 문제