C# 从使用id相互连接的行中提取信息
在sqlite中,有一个名为pathparts的表,该表包含3列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
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?这个问题是你之前回答的问题的延续,所以我在你之前回答的基础上添加了这个问题