简体   繁体   English

如何获取DbSet的主键?

[英]How can I get the Primary Key for the DbSet?

I use Net Core 1.1 and Entity Framework Core with the fluent API. 我使用Net Core 1.1和Entity Framework Core以及流畅的API。 I am writing a simple extension method for DbSet to show its entities in Console: 我正在为DbSet编写一个简单的扩展方法,以在Console中显示其实体:

public static class DbSetExtension
{
    public static void Show<T>(this DbSet<T> set) where T:class
    {

        WriteLine();
        WriteLine($"Set: {typeof(T).Name} - {set.Count()} objects.");
        WriteLine();

        foreach (var e in set)
        {
            WriteLine(e);
        }

        WriteLine();
        WriteLine();
    }
}

This works but I'd like to have the entities sorted by the primary key before showing them. 这有效,但我希望在显示之前让实体按主键排序。 If I had the DbContext it would have been easily accomplished by doing something like this: 如果我有DbContext ,可以通过这样的方式轻松完成:

var entityType = db.Model.FindEntityType(typeof(T));
var primaryKeyName = entityType.FindPrimaryKey().Properties.First().Name;
var set = db.Set<T>();
var orderedEntities = (set.OrderBy(e=> e.GetType().GetProperty(primaryKeyName).GetValue(e,null))).ToList();

Is there a way to get the same result starting from the DbSet ? 有没有办法从DbSet开始获得相同的结果?

It's possible, but not "officially" - you have to use some methods marked as This API supports the Entity Framework Core infrastructure and is not intended to be used directly from your code. 这可能,但不是“正式” - 您必须使用标记为此API的某些方法支持实体框架核心基础结构,并且不打算直接在您的代码中使用。 This API may change or be removed in future releases. 此API可能会在将来的版本中更改或删除。 .

You basically utilize the fact that DbSet<T> implements IInfrastructure<IServiceProvider> , so you can obtain IDbContextServices via GetService method in order to get the model from Model property: 您基本上利用了DbSet<T>实现IInfrastructure<IServiceProvider>这一事实,因此您可以通过GetService方法获取IDbContextServices ,以便从Model属性获取模型:

using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;

...
var model = set.GetService<IDbContextServices>().Model;
var entityType = model.FindEntityType(typeof(T));
var properties = entityType.GetProperties();
var primaryKeyName = entityType.FindPrimaryKey().Properties.First().Name;
var sortedSet = (set.OrderBy(e=> e.GetType().GetProperty(primaryKeyName).GetValue(e,null))).ToList();
...

I accepted Ivan Stoev's solution because it works so it is a very good answer to my question. 我接受了Ivan Stoev的解决方案,因为它有效,所以它是我的问题的一个非常好的答案。

But as Ivan pointed out GetService and IDbContextService API are marked as " This API supports the Entity Framework Core infrastructure and is not intended to be used directly from your code. This API may change or be removed in future releases.. " and I prefer to not use them in my code. 但正如Ivan所指出的, GetServiceIDbContextService API被标记为“ 此API支持实体框架核心基础结构,并不打算直接在您的代码中使用。此API可能会在将来的版本中更改或删除.. ”而我更喜欢不要在我的代码中使用它们。

An alternative approach that doesn't use internals and reflection would be to rewrite the extension method to accept the sorting property as a parameter.This would also increase its flexibility. 不使用内部和反射的替代方法是重写扩展方法以接受排序属性作为参数。这也将增加其灵活性。

I am posting this alternative solution because it may be useful to others with the same problem: 我发布这个替代解决方案,因为它可能对具有相同问题的其他人有用:

using System;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using static System.Console;

public static class DbSetExtension
{
    public static void ShowSortedBy<T,TKey>(this DbSet<T> set, Func<T,TKey> keySelector) where T:class
    {
        var sortedSet = set.OrderBy(x => keySelector(x)).ToList();

        WriteLine();
        WriteLine($"Set: {typeof(T).Name} - {set.Count()} objects.");
        WriteLine();

        foreach (var e in sortedSet)
        {
            WriteLine(e);
        }

        WriteLine();
        WriteLine();

    }
}

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

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