Linq 用POCO类定义链接的实体
我使用EF代码第一类 我有一个名为Linq 用POCO类定义链接的实体,linq,entity-framework,ef-code-first,Linq,Entity Framework,Ef Code First,我使用EF代码第一类 我有一个名为请求的实体: public class Request { [Key] public virtual int RequestID { get; set; } ... } 我需要相互链接请求 例如: 如果我们有下面定义的两个链接: RequestID 1链接到RequestID 2 RequestID 1链接到RequestID 3 然后 如果我们询问链接了哪些请求: (A) 对于1:结果是2,3 (B) 对于2:结果是1,3 (C
请求的实体:
public class Request
{
[Key]
public virtual int RequestID { get; set; }
...
}
我需要相互链接请求
例如:
如果我们有下面定义的两个链接:
- RequestID 1链接到RequestID 2
- RequestID 1链接到RequestID 3
然后
如果我们询问链接了哪些请求:
- (A) 对于1:结果是2,3
- (B) 对于2:结果是1,3
- (C) 对于3:结果是1,2
解释:
- 对于(A)项,很容易找到结果,因为链接是“直接的”
- 对于(B)和(C),这有点复杂,因为链接是通过1的“路径”检索的。我不知道我是否清楚
我的问题:定义链接模型类的最佳方式是什么?之后,如何查询(LINQ)这些模型类以检索如上所示的结果
起初,我认为链接模型类如下:(不知道这是否是个好主意)
以下结构可能正是您所寻找的:
实体
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; }
}
公共类请求
{
[关键]
公共虚拟int请求ID{get;set;}
...
//假设“1”与“2”和“3”相关
//“1”->“2”(1是关系的左侧;2是右侧)
//“1”->“3”(1是关系的左侧;3是右侧)
//对于“1”,它将返回“2”和“3”
//对于“2”,它将不返回任何内容
//对于“3”,它将不返回任何内容
公共虚拟ICollection请求链接{get;set;}
//对于“1”,它将不返回任何内容
//对于“2”,它将返回“1”
//对于“3”,它将返回“1”
公共虚拟ICollection请求链接此请求{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);
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasKey(i=>i.RequestID);
modelBuilder.Entity()
.HasKey(i=>new{i.RequestID,i.RequestRelatedID});
modelBuilder.Entity()
.HasMany(i=>i.requests链接)
.WithRequired(i=>i.RequestRelated)
.HasForeignKey(i=>i.RequestRelatedID)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.HasMany(i=>i.requests链接此请求)
.WithRequired(i=>i.Request)
.HasForeignKey(i=>i.RequestID)
.WillCascadeOnDelete(假);
基于模型创建(modelBuilder);
}
请参阅此链接
希望有帮助 我认为您的模型很好,但问题的本质很复杂,我认为没有有效的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的其他链接,并为其创建路径。已在路径中的路径行将被丢弃。最后,我们选择一个不同的id的数组s.
您可以在EF上下文中将此查询用作调用数据库.SqlQuery(…)
的函数
另一种选择是将所有链接加载到内存并构建一个完整的图,然后使用图算法查找路径。如果链接量较小,则可以使用此选项
另一个选项是将导航属性添加到请求
类,正如Fabio Luzpost建议的那样,在这种方法中,您可以递归地导航两个导航属性并检索子项,直到达到n
的深度。其中n
是引用的数量。
在这种方法中,您必须注意循环依赖关系,这可以通过保存一个遍历的请求列表来克服。
这种方法需要许多DB往返(需要连接以检索导航属性),因此如果路径深度较大,这可能不是一个选项。您能给我一些关于您的解决方案的解释吗?无论如何,谢谢你。看看代码里面的注释;这种关系适合你的情况吗?谢谢,我明天会试试,并与你保持联系。在这种情况下,你有两个导航属性。第一个将返回当前对象位于关系左侧的情况。第二个将返回当前对象位于关系右侧的情况。看看这篇文章末尾的链接。这可能有用。
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