【问题标题】:methods that are returning different return types返回不同返回类型的方法
【发布时间】:2020-01-23 17:01:58
【问题描述】:

我有以下方法,它们返回不同的实体,除了这些方法的输入参数都是相同的,我在 where 条件下使用这些方法

   public IQueryable<LibraryEnvironment> EnvironmentFields(string spaceFunction, string category, string source)
    {
        return _dbContext.LibraryEnvironment.Where(s => s.SpaceFunction == spaceFunction
                                                                && s.Category == category &&
                                                                 s.EnvironmentSource.Name == source);
    }

    public IQueryable<LibraryEquipment> EquipmentFileds(string spaceFunction, string category, string source)
    {
        return _dbContext.LibraryEquipment.Where(s => s.SpaceFunction == spaceFunction
                                                              && s.Category == category &&
                                                               s.EquipmentSource.Name == source);
    }

    public IQueryable<LibraryLighting> LightingFields(string spaceFunction, string category, string source)
    {
        return _dbContext.LibraryLighting.Where(s => s.SpaceFunction == spaceFunction
                                                             && s.Category == category &&
                                                              s.LightingSource.Name == source);
    }

还有其他类似的方法

我正在寻找一种在所有这些方法中创建通用泛型方法的方法,但返回类型不同,无法找到方法。我正在使用 .Net 核心和 EF 核心

如果有人对此提出任何想法,将非常感谢我,提前感谢

【问题讨论】:

  • 看看Generics,你可以接受一个Expression&lt;Func&lt;TInput, TOutputProperty&gt;&gt;来引入一个选择器让你选择s.EnvironmentSources.EquipmentSources.LightningSource
  • @ColinM 能否提供一些示例代码,不胜感激
  • s.EnvironmentSources.EquipmentSources.LightingSource 有共同的基本类型吗?我看到他们三个都有一个Name 属性。
  • @Sweeper 是的,它们都来自单个表并根据我们使用它们的实体重命名
  • 哦,所以它们都是同一类型?那它是什么类型的呢?

标签: c# .net entity-framework linq dynamic-linq


【解决方案1】:

您可以使用DbContext 上的Set&lt;T&gt; 方法来一般地访问集合。如果您将过滤所依据的所有相关属性放入一个基类中,您就可以将泛型参数限制为该基类类型,并且仍然过滤您的所有属性。

因此,根据您的原始查询,您的课程看起来像这样:

public class Entity
{
    public string SpaceFunction { get; set; }
    public string Category { get; set; }
}

public class LightingEquipment : Entity
{
    public LightingSource LightingSource { get; set; }
}

public class LightingSource
{
    public string Name { get; set; }
}

你的方法会喜欢这样,使用源选择器:

public IQueryable<T> Fields<T>(string spaceFunction, string category, string source, Func<T, string> sourceSelector) where T : Entity
{
    return _dbContext.Set<T>().Where(s => s.SpaceFunction == spaceFunction
                              && s.Category == category &&
                              sourceSelector(s) == source);
}

你会这样调用这个方法:

public void Consumer()
{
    var queryable = Fields<LightingEquipment>("spaceFunction", "category", "source", x => x.LightingSource.Name);
}

Docs for Set&lt;T&gt;()

【讨论】:

  • 感谢您的建议,我该如何调用此方法。
【解决方案2】:

我想你会发现你当前的设计是最干净的。您的代码并非完全“通用”,因为它们来自不同的表并具有不同的 where 子句(例如 s.EnvironmentSource.Name == sources.LightingSource.Name == source)。

可能能够组合一些功能,例如,按类型通用化表访问并组合过滤器的s.Category == category部分,但是您将混合使用反射(或 switch 语句)和泛型,这可能比您现在拥有的更难看。

【讨论】:

  • 非常感谢您的建议,我也可以使用 switch 语句
【解决方案3】:

如果您只想拥有 一个 方法,也许您可​​以摆脱泛型,正如@ColinM 在检查类型以确定要执行的代码块时提到的那样。
没有测试过,可能是错误的方法。这取决于你在哪里使用它。

public T Fields<T>(string spaceFunction, string category, string source)
{
    Type tt = typeof(T);
    if(tt == typeof(IQueryable<LibraryEnvironment>))
        return _dbContext.LibraryEnvironment.Where(s => s.SpaceFunction == spaceFunction
                                                        && s.Category == category &&
                                                          s.EnvironmentSource.Name == source);
    if (tt == typeof(IQueryable<LibraryEquipment>))
        return _dbContext.LibraryEquipment.Where(s => s.SpaceFunction == spaceFunction
                                                      && s.Category == category &&
                                                        s.EquipmentSource.Name == source);
    if (tt == typeof(IQueryable<LibraryLighting>))
        return _dbContext.LibraryLighting.Where(s => s.SpaceFunction == spaceFunction
                                                      && s.Category == category &&
                                                      s.LightingSource.Name == source);
    return default;
}

然后你可以调用指定返回类型的方法:

Fields<IQueryable<LibraryEnvironment>>("a", "b", "c");
Fields<IQueryable<LibraryEquipment>>("a", "b", "c");
Fields<IQueryable<LibraryLighting>>("a", "b", "c");

【讨论】:

  • 谢谢,但是如果您从这里Fields&lt;IQueryable&lt;LibraryEnvironment&gt;&gt;("a", "b", "c") 和方法Fields&lt;T&gt; 传递实体,是否可以删除如果条件.. 或任何其他方式
  • Fields&lt;IQueryable&lt;LibraryEnvironment&gt;&gt;("a", "b", "c")EnvironmentFields("a", "b", "c") 更可取吗?即使您对可查询部分进行了通用化,您仍然只有`Fields&lt;LibraryEnvironment&gt;("a", "b", "c"),这并不比原来的更好。
  • EnvironmentFields 将被“硬编码”。我觉得它好一点,但我完全明白你的意思。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多