使用POCO类定义链接的entites

时间:2015-08-21 16:12:23

标签: linq entity-framework ef-code-first

我使用EF Code First课程。

我有一个名为Request的实体:

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

我需要互相链接Request

例如:

如果我们有以下定义的2个链接:

  • RequestID 1链接到RequestID 2
  • RequestID 1链接到RequestID 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; }
}

2 个答案:

答案 0 :(得分: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

希望它有所帮助!

答案 1 :(得分: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 distinct id s [a sample on fiddle]数组Database.SqlQuery(...) 您可以在EF上下文中将此查询用作调用Request

的函数

另一个选择是将所有链接加载到内存并构建整个图形,然后使用图形算法查找路径。如果链接数量很小,则可以使用此选项。

另一个选项是将导航属性添加到n Fabio Luz 帖子建议,在这种方法中,您可以递归导航两个导航属性并检索子项,直到达到深度为n。其中Requests是参考数量 您必须了解此方法中的循环依赖,可以通过保留遍历的CREATE SEQUENCE food_id_ai START WITH 1 INCREMENT BY 1 CACHE 100; create table food( food_id integer, f_name varchar(30) not null, category varchar(30) not null, price number(4), amount number(4) ); alter table food add constraint fpk primary key(food_id); CREATE OR REPLACE TRIGGER insert_into_food BEFORE INSERT ON food FOR EACH ROW BEGIN :new.food_id:= food_id_ai.nextval; END; / insert into food values(food_id_ai.nextval,'ruchi', 'chanachur' , 8, 50); insert into food values(food_id_ai.nextval,'chips', 'chips' , 8, 50); insert into food values(food_id_ai.nextval,'aeromatic', 'soap' , 8, 50); insert into food values(food_id_ai.nextval,'handwash', 'toyletries', 8, 50); insert into food values(food_id_ai.nextval,'tissue', 'toyletries' , 8, 50); 列表来克服。 这种方法需要许多数据包往返(需要连接来检索导航属性),所以如果路径的深度很大,这可能不是一个选项。