简体   繁体   English

EF Core从多重性为零或一的模型中获取实体的导航属性

[英]EF Core get Navigation Properties of an entity from Model with multiplicity Zero or One

I am creating a generic class to seed the database with Entities, needed for integration tests. 我正在创建一个通用类,以使用集成测试所需的实体来为数据库添加种子。 I can create individual entities but when one depends from another, I have to manually instruct my class first create the parent entity and then proceed. 我可以创建单个实体,但是当一个实体彼此依赖时,我必须手动指示班级首先创建父实体,然后继续。 I am trying to make this detection automatic, getting from the Model definition, the list of navigation properties with multiplicity 0 or 1 (Reference navigation properties), once that is done, recursively my class will invoke itself to create parent entities first (Circular dependencies are out of scope here). 我试图使这种检测自动进行,从模型定义中获取多重性为0或1的导航属性列表(参考导航属性),一旦完成,递归地我的类将首先调用自身以创建父实体(循环依赖)在此超出范围)。

I used to do this in EF for .net Framework, but EF Core has changed a lot. 我曾经在.net Framework EF中执行此操作,但EF Core发生了很大变化。 What I am missing in EF Core is the RelationshipMultiplicity , I cannot find any reference to Multiplicity in the official documentation, and even tough the hacky solution is to check if the navigation property is a collection, I would like to have more control and keeps things simple. 我在EF Core中缺少的是RelationshipMultiplicity ,我在官方文档中找不到任何对Multiplicity的引用,甚至棘手的解决方案是检查导航属性是否为集合,我想拥有更多控制权并保留所有东西简单。

So far I am exploring the Model definition using: 到目前为止,我正在使用以下方法探索模型定义:

var modelData = _context.Model.GetEntityTypes()
    .Select(t => new
    {
        t.ClrType.Name,
        DerivedNavigationProperties = t.FindDerivedNavigations(t.ClrType.Name),
        DefiningNavigationProperties = t.FindDefiningNavigation(),
        DeclaredForeignKeys = t.GetDeclaredForeignKeys(),
        DeclaredNavigations = t.GetDeclaredNavigations(),
        DerivedNavigations = t.GetDerivedNavigations(),
        DerivedNavigationsInclusive = t.GetDerivedNavigationsInclusive(),
        Navigations = t.GetNavigations() // This returns all Navigation Properties (INavigation)
    });

After inspecting the source code in GitHub, I can say with enough confidence that there is no such thing as Multiplicity in EF Core. 在检查了GitHub中的源代码之后,我可以很有把握地说,EF Core中没有诸如Multiplicity之类的东西。

I created an enumeration like the one used .net Framework 3.5+ (See: Official documentation ): 我创建了一个枚举,类似于使用的.net Framework 3.5+(请参阅: 官方文档 ):

public enum RelationshipMultiplicity
{
    Many = 2,
    One = 1,
    ZeroOrOne = 0
}

And then an extension method which allows getting all navigation properties using the enum as a filter. 然后是扩展方法,该方法允许使用枚举作为过滤器来获取所有导航属性。 The key things I used are: 我使用的关键是:

The method allows to get all Navigations properties by relation type 该方法允许按关系类型获取所有Navigations属性

public static class ModelExtensions
{
    /// <summary>
    /// Extension method used to get from the entity all navigation properties by multiplicity
    /// </summary>
    /// <typeparam name="T">Entity from where the navigation properties are taken</typeparam>
    /// <param name="model">Context Model</param>
    /// <param name="multiplicity">Type of multiplicity to use</param>
    /// <returns>List of PropertyInfo of Navigation Properties</returns>
    public static IEnumerable<PropertyInfo> GetNavigationProperties<T>(this IModel model, RelationshipMultiplicity multiplicity)
    {
        var navigations = model.GetEntityTypes().FirstOrDefault(m => m.ClrType == typeof(T))?.GetNavigations();
        var properties = new List<PropertyInfo>();

        switch (multiplicity)
        {
            case RelationshipMultiplicity.Many | RelationshipMultiplicity.ZeroOrOne:
                return navigations?
                    .Select(nav => nav.PropertyInfo);
            case RelationshipMultiplicity.Many:
                return navigations?
                    .Where(nav => nav.IsCollection())
                    .Select(nav => nav.PropertyInfo);
            case RelationshipMultiplicity.One:
                return navigations?
                    .Where(nav => !nav.IsCollection() && nav.ForeignKey.IsRequired)
                    .Select(nav => nav.PropertyInfo);
            case RelationshipMultiplicity.ZeroOrOne:
                return navigations?
                    .Where(nav => !nav.IsCollection())
                    .Select(nav => nav.PropertyInfo);
            default:
                return null;
        }

        return properties;
    }
}

Usage example: 用法示例:

var oneToManyRelations = _context.Model.GetNavigationProperties<Transaction>(
    RelationshipMultiplicity.ZeroOrOne);

var manyToOneRelations = _context.Model.GetNavigationProperties<Transaction>(
    RelationshipMultiplicity.Many);

var allRelations = _context.Model.GetNavigationProperties<Transaction>(
    RelationshipMultiplicity.Many | 
    RelationshipMultiplicity.ZeroOrOne);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM