2015-08-21 63 views
2

我使用EF Code First類。使用POCO類定義鏈接實體

我有一個實體命名爲Request

public class Request 
{ 
    [Key] 
    public virtual int RequestID { get; set; } 
    ... 
} 

我需要鏈接Request對方。

例如:

,如果我們有如下定義的2個鏈接:

  • 請求ID 1被鏈接到請求ID 2
  • 請求ID 1被鏈接到請求ID 3

THEN ...

如果我們要求將請求連接:

  • (A)爲1:結果是2,3
  • (B)爲2:結果是1,3-
  • (C)爲3 :結果是1,2

說明:

  • 對於(A)這是很容易找到的結果,因爲該鏈接是 「直接」
  • 對於(B)和(C),這有點複雜,因爲鏈接是通過遵循'路徑'通過1來檢索的。我不知道我是否清楚。

我的問題:什麼是定義鏈接模型類的最好方法?之後,如何查詢(LINQ)這些模型類來檢索如上所示的結果?

起初,我以爲下面的鏈接模型類:(不知道這是不是一個好主意)

public class RequestLinked 
{ 
    [Key, Column(Order = 0)] 
    [ForeignKey("Request")] 
    public int RequestID { get; set; } 

    [Key, Column(Order = 1)] 
    [ForeignKey("RequestRelated")] 
    public int RequestRelatedID { get; set; } 

    public virtual Request Request { get; set; } 
    public virtual Request RequestRelated { get; set; } 
} 

回答

0

下面的結構可能是你在找什麼:

實體

public class Request 
{ 
    [Key] 
    public virtual int RequestID { get; set; } 
    ... 
    // Suppose that "1" is related to "2" and "3" 
    // "1" -> "2" (1 is the left side of relationship; 2 is the right side) 
    // "1" -> "3" (1 is the left side of relationship; 3 is the right side) 

    // For "1" it will return "2" and "3" 
    // For "2" it will return nothing 
    // For "3" it will return nothing 
    public virtual ICollection<RequestLinked> RequestsLinked { get; set; } 

    // For "1" it will return nothing 
    // For "2" it will return "1" 
    // For "3" it will return "1" 
    public virtual ICollection<RequestLinked> RequestsLinkedThisRequest { get; set; } 
} 

映射

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Request>() 
     .HasKey(i => i.RequestID); 

    modelBuilder.Entity<RequestLinked>() 
     .HasKey(i => new {i.RequestID, i.RequestRelatedID }); 

    modelBuilder.Entity<Request>() 
     .HasMany(i => i.RequestsLinked) 
     .WithRequired(i => i.RequestRelated) 
     .HasForeignKey(i => i.RequestRelatedID) 
     .WillCascadeOnDelete(false); 

    modelBuilder.Entity<Request>() 
     .HasMany(i => i.RequestsLinkedThisRequest) 
     .WithRequired(i => i.Request) 
     .HasForeignKey(i => i.RequestID) 
     .WillCascadeOnDelete(false); 


    base.OnModelCreating(modelBuilder); 
} 

看到這個鏈接Entity Framework - Fluent APi - Create table with 2 FK

希望它有幫助!

+0

你能給我解釋一下你的解決方案嗎?不管怎麼說,還是要謝謝你。 – Bronzato

+0

我弄錯了......我會編輯答案 –

+0

看看代碼中的註釋;這種關係適合你的情況? –

0

我認爲你的模型是好的,但問題的本質是複雜的,我不認爲有一個有效的LINQ查詢來檢索路徑。因爲檢索路徑需要遞歸移動請求的左側和右側。你所能做的最好的是使用我認爲的SQL遞歸查詢。事情是這樣的:

WITH cte AS ( 
      SELECT RequestLink.*, cast('(' + cast(RequestId as nvarchar(max)) + ',' 
        + cast(RequestRelatedId as nvarchar(max))+')' as nvarchar(max)) Path 
       FROM RequestLink 
       WHERE RequestId = 3 OR RequestRelatedId = 3 
       UNION ALL 

       SELECT a.*, 
        cast(
         c.Path + '(' + 
         cast(a.RequestId as nvarchar(max)) + ',' + 
         cast(a.RequestRelatedId as nvarchar(max)) + ')' 
         as nvarchar(max) 
         ) Path 
      FROM RequestLink a JOIN cte c ON 
        a.RequestId = c.RequestRelatedId 
        OR c.RequestId = a.RequestRelatedId 
        OR c.RequestId = a.RequestId 
        OR c.RequestRelatedId = a.RequestRelatedId 
       where c.Path not like cast(
         '%(' + 
         cast(a.RequestId as nvarchar(max)) + ',' + 
         cast(a.RequestRelatedId as nvarchar(max)) + 
         ')%' 
         as nvarchar(max) 
         ) 

) 
    SELECT DISTINCT id from (
    SELECT distinct RequestId as id FROM cte 
    union all 
    SELECT distinct RequestRelatedId as id FROM cte 
) a 

此查詢首先找到id=3然後遞歸附加有一個共同的ID與它的其他環節,併爲它創建一個路徑。已經在路徑中的路徑行將被丟棄。最後我們select a distinct陣列id s。 [a sample on fiddle]
您可以在EF上下文中將此查詢用作調用Database.SqlQuery(...)的函數。

另一種方法是將所有鏈接加載到內存中,然後構建一個完整的圖形,然後使用圖形算法查找路徑。如果鏈接量很小,可以使用此選項。

的另一種選擇是導航屬性添加到Request類爲法比奧·盧斯後建議,在這種方法中,你可以遞歸導航兩種導航性能和檢索的孩子,直到你到達的n深度。其中n是引用的數量。
您必須瞭解循環依賴關係,這種方法可以通過保留遍歷的列表Requests來克服。 這種方法需要很多數據庫往返行程(需要連接來檢索導航屬性),所以如果路徑的深度很大,這可能不是一個選項。