[英]EF Core relationship without foreign key
如何在不聲明外鍵的情況下設置導航屬性?
我有兩個表( segment
和category
),它們可以使用 2 列(origin/destination)連接,但它們不滿足外鍵約束,因為它們可以具有另一個表中不存在的值(所以它不是關於null 或不為空)
部分
Id Date OriginId DestinationId
---------------------------------------
1 2020-01-10 1 2
2 2020-01-18 2 1
2 2020-02-05 1 3
4 2020-04-11 3 3
類別
Id OriginId DestinationId Category
-----------------------------------------
1 1 2 Primary
2 2 1 Secondary
2 2 3 Primary
我想知道每個Segment
類別。 但並非每個細分都存在於Category
中,因此某些細分不會有類別。
這個 SQL 工作:
SELECT
s.*, c.name
FROM
Segment s
LEFT OUTER JOIN
Category c ON c.originId = s.originId AND c.destinationId = s.destinationId
這個 LINQ 也可以:
from s in Segment
join c in Category on new { s.OriginId, s.DestinationId } equals new { c.OriginId, c.DestinationId } into grouping
from c in grouping.DefaultIfEmpty()
select new { s, c };
但是要使用導航,我得到的最接近的是:我分別在每個 class 上添加了一個屬性,並使用流利的 api 在上下文中設置關系
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Segment>()
.HasOne(segment => segment.Category)
.WithMany(category => category.Segments)
.HasForeignKey(segment => new { segment.OriginId, segment.DestinationId })
.HasPrincipalKey(category => new { category.OriginId, category.DestinationId })
.IsRequired(false);
}
// then I can do
var query = Segments.Include(o => o.Category).ToList();
這可以檢索數據庫中已經存在的記錄。
但是要在 Category 中不存在 originId 和 destinationId 的 Segment 中插入一條新記錄,它會抱怨 originId 和 destinationId 不滿足外鍵約束。 沒關系,因為它們不存在於另一個表中。
它們實際上不是外鍵,只是用於連接它們的列,但我不知道如何使用導航屬性 + Fluent Api 來設置它。
第一的:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "<掛起>")]
public class MigrationsModelDifferWithoutForeignKey : MigrationsModelDiffer
{
public MigrationsModelDifferWithoutForeignKey
([NotNull] IRelationalTypeMappingSource typeMappingSource,
[NotNull] IMigrationsAnnotationProvider migrationsAnnotations,
[NotNull] IChangeDetector changeDetector,
[NotNull] IUpdateAdapterFactory updateAdapterFactory,
[NotNull] CommandBatchPreparerDependencies commandBatchPreparerDependencies)
: base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies)
{
}
public override IReadOnlyList<MigrationOperation> GetDifferences(IModel source, IModel target)
{
var operations = base.GetDifferences(source, target)
.Where(op => !(op is AddForeignKeyOperation))
.Where(op => !(op is DropForeignKeyOperation))
.ToList();
foreach (var operation in operations.OfType<CreateTableOperation>())
operation.ForeignKeys?.Clear();
return operations;
}
}
如何使用:
services.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer(Default);
options.ReplaceService<IMigrationsModelDiffer, MigrationsModelDifferWithoutForeignKey>();
});
抱歉 - 這個聚會有點晚了。
我剛剛經歷了類似的練習。 你可以試試這個:
modelBuilder.Entity<Category>()
.HasMany(category => category.Segments)
.WithOne(segment => segment.Category)
.HasPrincipalKey(category => new { category.OriginId, category.DestinationId })
.IsRequired(false)
.OnDelete(DeleteBehavior.NoAction);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.