我想使用 Entity Framework Core 8(仅)从我无法修改的数据库(首先是数据库)读取,并且该数据库不包含显式外键。因此,在搭建脚手架之后,我需要手动定义关系。我需要帮助定义两个表之间的关系,该关系可以直接通过外键,也可以通过第三个表间接(如果未定义外键)。
考虑以下实体
public partial class Procedure
{
[key]
public string ProcedureId { get; set; }
public string ProcedureName { get; set; }
// Foreign keys
public string DocumentBaseId { get; set; }
public string SpecificVersionId { get; set; }
// Navigation properties
public DocumentBase DocumentBase { get; set; }
public DocumentVersion SpecificVersion { get; set; }
}
public class DocumentBase
{
[key]
public string DocumentBaseId { get; set; }
public string DocumentName { get; set; }
// Foreign key
public string DefaultVersionId { get; set; }
// Navigation properties
public ICollection<DocumentVersion > DocumentVersions { get; set; } = new List<DocumentVersion >();
public DocumentVersion DefaultVersion { get; set; }
}
public class DocumentVersion
{
[key]
public string DocumentVersionId { get; set; }
public string VersionName { get; set; }
// Foreign keys
public string DocumentBaseId { get; set; }
public string AuthorId { get; set; }
// Navigation properties
public DocumentBase DocumentBase { get; set; }
public Author Author { get; set; }
}
public class Author
{
[key]
public string AuthorId { get; set; }
public string AuthorName { get; set; }
// Navigation property
public ICollection<DocumentVersion > DocumentVersions { get; set; } = new List<DocumentVersion >();
}
以及以下上下文
modelBuilder.Entity<Procedure>()
.HasOne(p => p.DocumentBase)
.WithOne()
.HasForeignKey<Procedure>(p => p.DocumentBaseId)
.IsRequired();
modelBuilder.Entity<Procedure>()
.HasOne(p => p.SpecificVersion)
.WithOne()
.HasForeignKey<Procedure>(p => p.SpecificVersionId);
modelBuilder.Entity<DocumentBase>()
.HasOne(db => db.DefaultVersion)
.WithOne()
.HasForeignKey<DocumentBase>(db => db.DefaultVersionId);
modelBuilder.Entity<DocumentVersion>()
.HasOne(dv => dv.DocumentBase)
.WithMany(db => db.DocumentVersions)
.HasForeignKey(dv => dv.DocumentBaseId)
.IsRequired();
modelBuilder.Entity<DocumentVersion>()
.HasOne(dv => dv.Author)
.WithMany(a => a.DocumentVersions)
.HasForeignKey(dv => dv.AuthorId)
.IsRequired();
如何定义关系
public partial class Procedure
{
// Another navigation property
public DocumentVersion CurrentVersion => SpecificVersion ?? DocumentBase.DefaultVersion;
}
这样查询就可以使用这种关系?例如
string author = context.Procedures.FirstOrDefault(p => p.ProcedureName == "p1").CurrentVersion.Author;
关系的等效 SQL 是
from Procedure p
join DocumentVersion dv join DocumentBase db on dv.DocumentBaseId == db.DocumentBaseId on ((p.SpecificVersionId = dv.DocumentVersionId) or (p.DocumentBaseId = db.DocumentBaseId and db.DefaultVersionId = dv.DocumentVersionId))
我尝试简单地添加只读属性,但它导致了 NullReferenceException。
我尝试了外键的复杂表达式
modelBuilder.Entity<Procedure>()
.HasOne(p => p.DocumentVersion)
.WithOne()
.HasForeignKey<Procedure>(p => p.SpecificVersionId ?? p.DocumentBase.DefaultVersionId);
但这不受支持。
Entity Framework Core 不支持非简单外键的关系。 EF Core 工具和扩展页面描述了可与 Entity Framework Core 一起使用的扩展。我选择了linq2db.EntityFrameworkCore。
var query = from p in context.Procedure
where p.ProcedureId == Identifier
from db in context.DocumentBase
from dv in context.DocumentVersion.Where(
dv => dv.DocumentBaseId == db.DocumentBaseId &&
(dv.DocumentVersionId == p.SpecificVersionId ||
p.DocumentBaseId == db.DocumentBaseId && dv.DocumentVersionId == db.DefaultVersionId))
select new
{
Version = dv.VersionName,
};