C# 从使用id相互连接的行中提取信息

C# 从使用id相互连接的行中提取信息,c#,entity-framework-core,C#,Entity Framework Core,在sqlite中,有一个名为pathparts的表,该表包含3列 rowId | parent | pathpart 这些行如下所示 rowId | parent | pathpart -------------------------- 1 | null | manifests 100 | 1 | h 154 | 100 | publisher 184 | 154 | appname 654 | 184 | version 985

在sqlite中,有一个名为pathparts的表,该表包含3列

rowId | parent | pathpart
这些行如下所示

rowId | parent | pathpart
--------------------------
1     | null   | manifests
100   | 1      | h
154   | 100    | publisher
184   | 154    | appname
654   | 184    | version
985   | 654    | url
1452  | 1      | f
1460  | 1452   | publisher
2456  | 1460   | appname
3456  | 2456   | url
from manifest in msixDB.Set<ManifestMSIXTable>().Where(e => e.id == item.rowid)

                from yml in msixDB.PathPartsMSIXTable.Where(e => e.rowid == manifest.pathpart)
                
                from pathPart in pathCte.Where(e => e.rowid == yml.parent && e.parent == null)
                from version in msixDB.VersionsMSIXTable.Where(e => e.rowid == manifest.version)
                select new ManifestTable
                {
                    PackageId = item.id,
                    YamlName = $@"{pathPart.path}\{yml.pathpart}",
                    Version = version.version
                };
如您所见,每一行都包含一个父行,父行将其连接到另一行,它们最终都连接到父行1(这是Microsoft for Winget软件),如果我们将这些行按顺序放在一起,它将创建包的规范,例如:

h\microsoft\vscode\1.0.1.0\url.yml
我可以用下面的代码提取这些信息

var query =
    from item in msixDB.IdsMSIXTable
    from manifest in msixDB.Set<ManifestMSIXTable>().Where(e => e.id == item.rowid)
    
    from yml in msixDB.PathPartsMSIXTable.Where(e => e.rowid == manifest.pathpart).Take(1).DefaultIfEmpty()
    from pathPartVersion in msixDB.PathPartsMSIXTable.Where(e => e.rowid == yml.parent).Take(1).DefaultIfEmpty()
    from pathPartAppName in msixDB.PathPartsMSIXTable.Where(e => e.rowid == pathPartVersion.parent).Take(1).DefaultIfEmpty()
    from pathPartPublisher in msixDB.PathPartsMSIXTable.Where(e => e.rowid == pathPartAppName.parent).Take(1).DefaultIfEmpty()
    from pathPart in msixDB.PathPartsMSIXTable.Where(e => e.rowid == pathPartPublisher.parent).Take(1).DefaultIfEmpty()
    from version in msixDB.VersionsMSIXTable.Where(e => e.rowid == manifest.version).Take(1).DefaultIfEmpty()
    select new ManifestTable
    {
        PackageId = item.id,
        YamlName = $@"{pathPart.pathpart}\{pathPartPublisher.pathpart}\{pathPartAppName.pathpart}\{pathPartVersion.pathpart}\{yml.pathpart}",
        Version = version.version
    };

mydb.ManifestTable.AddRange(await query.ToListAsync());
更新2:

我稍微修改了您编写的代码,结果如下

rowId | parent | pathpart
--------------------------
1     | null   | manifests
100   | 1      | h
154   | 100    | publisher
184   | 154    | appname
654   | 184    | version
985   | 654    | url
1452  | 1      | f
1460  | 1452   | publisher
2456  | 1460   | appname
3456  | 2456   | url
from manifest in msixDB.Set<ManifestMSIXTable>().Where(e => e.id == item.rowid)

                from yml in msixDB.PathPartsMSIXTable.Where(e => e.rowid == manifest.pathpart)
                
                from pathPart in pathCte.Where(e => e.rowid == yml.parent && e.parent == null)
                from version in msixDB.VersionsMSIXTable.Where(e => e.rowid == manifest.version)
                select new ManifestTable
                {
                    PackageId = item.id,
                    YamlName = $@"{pathPart.path}\{yml.pathpart}",
                    Version = version.version
                };
来自msixDB.Set()中的清单,其中(e=>e.id==item.rowid)
从msixDB.pathPartsMaxTable.Where(e=>e.rowid==manifest.pathpart)中的yml开始
从pathCte.Where中的pathPart(e=>e.rowid==yml.parent&&e.parent==null)
从msixDB.VersionsMSIXTable.Where(e=>e.rowid==manifest.version)中的版本开始
选择新表
{
PackageId=item.id,
YamlName=$@“{pathPart.path}\{yml.pathPart}”,
Version=Version.Version
};
现在一切正常,只是有些行没有添加

微软数据库

将项目添加到数据库后


如您所见,对于这样的任务,只添加了1行,您需要递归CTE,而EF任何版本都不支持。我建议使用扩展,将这些功能引入现有的EF核心项目

类路径 { 公共长rowid{get;set;} 公共长?父{get;set;} 公共字符串路径{get;set;} }
使用var msixDB=new MSIXContext();
var mydb=new HWGContext();
等待mydb.Database.EnsureDeletedAsync();
等待mydb.Database.EnsureCreatedAsync();
使用var db=msixDB.CreateLinqToDbConnection();
var pathCte=db.GetCte(cte=>(
从msixDB.PathPartsMaxTable中的pathPart
选择新路径
{
rowid=pathPart.rowid,
parent=pathPart.parent,
path=pathPart.pathPart
}
)
康卡特先生(
从msixDB.PathPartsMaxTable中的pathPart
从cte.Where(child=>child.parent==pathPart.rowid)中的子级
选择新路径
{
rowid=child.rowid,
parent=pathPart.parent,
path=pathPart.pathPart+“\\”+子路径
}       
)
);
变量查询=
从msixDB.idsmisxtable中的项
来自msixDB.Set()中的清单,其中(e=>e.id==item.rowid)
从msixDB.pathPartsMaxTable.Where(e=>e.rowid==manifest.pathpart)中的yml开始
从msixDB.pathPartsMaxTable.Where(e=>e.rowid==yml.parent)中的pathPartVersion
来自msixDB.pathPartsMaxTable.Where(e=>e.rowid==pathPartVersion.parent)中的pathPartAppName
来自msixDB.pathPartsMaxTable.Where(e=>e.rowid==pathPartAppName.parent)中的pathPartPublisher
从pathCte.Where中的pathPart(e=>e.rowid==pathPartPublisher.parent&&e.parent==null)
从msixDB.VersionsMSIXTable.Where(e=>e.rowid==manifest.version)中的版本开始
选择新表
{
PackageId=item.id,
YamlName=$@“{pathPart.path}{pathPartPublisher.pathPart}{pathPartAppName.pathPart}{pathPartVersion.pathPart}{yml.pathPart}”,
Version=Version.Version
};
var data=await query.ToArrayAsyncLinqToDB();
mydb.AddRange(数据);
等待mydb.saveChangesSync();

我觉得您选择了不好的ORM来完成任务。在这种情况下,您需要CTE。如果您同意,我将使用此扩展名准备示例:,请注意,我是此扩展名的创建者。@SvyatoslavDanyliv我没有太多地使用数据库,所以我做得不够,我同意,您可以使用
PathPartsMaxTable
类定义更新问题吗?@SvyatoslavDanyliv doneall我也必须使用
LinqToDBForEFTools.Initialize()?谢谢,但是我在
mydb.BulkCopy(query.ToLinqToDB())中发现了一个错误
Microsoft.Data.Sqlite.SqliteException:'Sqlite错误19:'UNIQUE constraint failed:manifests.Id'。
,我还在
PathCte
中将
int
更改为
long
,添加了
。Take(1).DefaultIfEmpty()
到行尾,现在我得到另一个错误
数据库不支持查询所需的交叉/外部应用联接1)你。可以使用EF保存更改。2) 为什么添加Take(1).DeefaultIfEmpty()?我应该删除
mydb.BulkCopy
并使用SaveChanges?这个问题是你之前回答的问题的延续,所以我在你之前回答的基础上添加了这个问题