我使用EF Code First课程。
我有一个名为Request
的实体:
public class Request
{
[Key]
public virtual int RequestID { get; set; }
...
}
我需要互相链接Request
。
例如:
如果我们有以下定义的2个链接:
THEN ...
如果我们询问链接了哪些请求:
说明:
我的问题:定义链接模型类的最佳方法是什么?之后,如何查询(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 :(得分: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);
列表来克服。
这种方法需要许多数据包往返(需要连接来检索导航属性),所以如果路径的深度很大,这可能不是一个选项。