gpt4 book ai didi

c# - 如何定义类内封装属性的导航?

转载 作者:行者123 更新时间:2023-12-04 04:30:24 26 4
gpt4 key购买 nike

我继承了一个共享项目,其中定义了模型。为了更容易的 XML 序列化,它们采用以下形式:

    public class Blog
{
public int Id { get; set; }
public Posts Posts { get; set; }
}

public class Posts
{
public List<Post> PostsCollection { get; set; }
}

public class Post
{
public int BlogId { get; set; }
public int PostId { get; set; }
public string Content { get; set; }
}
如何在 OnModelCreating 中指定 EF DbContext使用方法 Posts.PostsCollection作为导航属性?让我们假设,我不允许在 Post 和 Blog 类中更改任何内容。我只需要以编程方式指定 EF 的关系。是否可以?我读过 defining relationships on MS site以及有关在本网站和其他各种网站上定义模型的其他主题,但找不到适合我的场景的任何内容。

最佳答案

这是可能的,但中间类必须映射为假实体,作为一对多关系的主体,并依赖于与实际主体的一对一关系。
拥有的实体类型看起来不错,但由于 EF Core 不允许拥有的实体类型作为主体的限制,它必须配置为与“所有者”共享同一张表的常规“实体”(所谓的表拆分) 和影子“PK”/“FK”属性实现所谓的共享主键关联。
由于中间的“实体”和与所有者的“关系”是通过影子属性处理的,因此涉及的模型类都不需要修改。
以下是示例模型的流畅配置

modelBuilder.Entity<Posts>(entity =>
{
// Table splitting
entity.ToTable("Blogs");
// Shadow PK
entity.Property<int>(nameof(Blog.Id));
entity.HasKey(nameof(Blog.Id));
// Ownership
entity.HasOne<Blog>()
.WithOne(related => related.Posts)
.HasForeignKey<Posts>(nameof(Blog.Id));
// Relationship
entity
.HasMany(posts => posts.PostsCollection)
.WithOne()
.HasForeignKey(related => related.BlogId);
});
影子 PK/FK 属性的名称可以是任何名称,但您需要知道所有者表名称/模式以及 PK 属性名称和类型。所有这些信息都可以从 EF Core 模型元数据中获得,因此可以将更安全和可重用的配置提取到这样的自定义扩展方法中(EF Core 3.0+,可以针对 2.x 进行调整)
namespace Microsoft.EntityFrameworkCore
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Metadata.Builders;

public static class CustomEntityTypeBuilderExtensions
{
public static CollectionNavigationBuilder<TContainer, TRelated> HasMany<TEntity, TContainer, TRelated>(
this EntityTypeBuilder<TEntity> entityTypeBuilder,
Expression<Func<TEntity, TContainer>> containerProperty,
Expression<Func<TContainer, IEnumerable<TRelated>>> collectionProperty)
where TEntity : class where TContainer : class where TRelated : class
{
var entityType = entityTypeBuilder.Metadata;
var containerType = entityType.Model.FindEntityType(typeof(TContainer));
// Table splitting
containerType.SetTableName(entityType.GetTableName());
containerType.SetSchema(entityType.GetSchema());
// Shadow PK
var key = containerType.FindPrimaryKey() ?? containerType.SetPrimaryKey(entityType
.FindPrimaryKey().Properties
.Select(p => containerType.FindProperty(p.Name) ?? containerType.AddProperty(p.Name, p.ClrType))
.ToArray());
// Ownership
entityTypeBuilder
.HasOne(containerProperty)
.WithOne()
.HasForeignKey<TContainer>(key.Properties.Select(p => p.Name).ToArray());
// Relationship
return new ModelBuilder(entityType.Model)
.Entity<TContainer>()
.HasMany(collectionProperty);
}
}
}
使用上面的自定义方法,示例模型的配置将是
modelBuilder.Entity<Blog>()
.HasMany(entity => entity.Posts, container => container.PostsCollection)
.WithOne()
.HasForeignKey(related => related.BlogId);
如果集合导航属性直接位于 Blog 上,则这与标准配置几乎相同(只有一个额外的 lambda 参数)
modelBuilder.Entity<Blog>()
.HasMany(entity => entity.PostsCollection)
.WithOne()
.HasForeignKey(related => related.BlogId);

关于c# - 如何定义类内封装属性的导航?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65807844/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com