[英]EF Core relationship without foreign key
How to setup a navigation property without declaring a foreign key?如何在不声明外键的情况下设置导航属性?
I have two tables ( segment
and category
), they can join using 2 columns (origin/destination) but they don't meet the foreign key constraint because they can have value that doesn't exist in the other table (so its not about null or not null)我有两个表( segment
和category
),它们可以使用 2 列(origin/destination)连接,但它们不满足外键约束,因为它们可以具有另一个表中不存在的值(所以它不是关于null 或不为空)
Segment部分
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
Category类别
Id OriginId DestinationId Category
-----------------------------------------
1 1 2 Primary
2 2 1 Secondary
2 2 3 Primary
I want to know every Segment
category.我想知道每个Segment
类别。 But not every segment exists in Category
so some segments won't have a category.但并非每个细分都存在于Category
中,因此某些细分不会有类别。
This SQL works:这个 SQL 工作:
SELECT
s.*, c.name
FROM
Segment s
LEFT OUTER JOIN
Category c ON c.originId = s.originId AND c.destinationId = s.destinationId
This LINQ also works:这个 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 };
But to use navigation, closest I got is this: I added a property on each class respectively and setup the relationship in context using fluent api但是要使用导航,我得到的最接近的是:我分别在每个 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();
This works to retrieve records that already exists in the database.这可以检索数据库中已经存在的记录。
But to insert a new record to Segment where originId and destinationId do not exists in Category it complains about originId and destinationId not meeting the foreign key constraint.但是要在 Category 中不存在 originId 和 destinationId 的 Segment 中插入一条新记录,它会抱怨 originId 和 destinationId 不满足外键约束。 And it's ok because they don't exist in the other table.没关系,因为它们不存在于另一个表中。
They actually aren't foreign keys, just a column to use for joining them, but I don't khow to set this using a navigation property + Fluent Api.它们实际上不是外键,只是用于连接它们的列,但我不知道如何使用导航属性 + Fluent Api 来设置它。
First:第一的:
[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;
}
}
How to use:如何使用:
services.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer(Default);
options.ReplaceService<IMigrationsModelDiffer, MigrationsModelDifferWithoutForeignKey>();
});
Sorry - a bit late to this party.抱歉 - 这个聚会有点晚了。
I just went through a similar excercise.我刚刚经历了类似的练习。 You could try this:你可以试试这个:
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.