【问题标题】:Generically return an item from Entity Framework通常从实体框架返回一个项目
【发布时间】:2011-02-19 06:45:24
【问题描述】:

我有一种情况,网站可以根据字符串从我的数据库中请求数据(别担心 - 我正在防止 SQL 注入)。出于各种原因,我希望有一个方法可以返回用户期望的对象(来自 EF)(最终通过部分页面返回)。

我在想这样的事情:

public <GenericType?> GetObject(int id, string typeName) {
  switch(typeName) {
    case "Type1":
      return db.Type1s.SingleOrDefault(t => t.TypeID == id);
    case "Type2":
      return db.Type2.SingleOrDefault(t => t.TypeID == id);
    default:
      return null;
  }
}

有可能做这样的事情吗? (我要避免的是必须提前执行 switch 语句,然后调用特定的 Repository 方法,因为我必须重复代码并多次执行此操作。)

【问题讨论】:

  • 我很想推荐一个动态解决方案,但是动态对象不能调度扩展方法(如IEnumerable&lt;T&gt;.Where),表达式树不能有动态操作。
  • 看看WCF Data Services,以前称为“ADO.NET 数据服务”。
  • Adam - 我确信这可以使用表达式树来实现...
  • @flesh - 我知道你可以,但我不知道这有多容易。我需要真正深入了解表达式树。

标签: c# generics entity-framework-4


【解决方案1】:

CreateQuery&lt;T&gt; 可能是您需要的。

Does the Entity Framework have an equivalent of DataContext.GetTable<TEntity> from Linq2Sql (ObjectContext.CreateQuery<T>?)

有什么方法可以让您传入的所有可能类型与具有此 TypeID 属性的特定接口相匹配?如果是这样,怎么样:

    public T GetResult<T>(int id, string typeName) where T : IClassWithTypeID {
        YourEntities db = new YourEntities();
        var result = db.CreateQuery<T>(String.Format("[{0}]", typeName));

        return result.Single(t => t.TypeID == id);
    }

【讨论】:

    【解决方案2】:

    实际上,任何类型的通用报告生成器/查询执行器等都可能比尝试将动态逻辑适合 EF 或 LINQ 更好地使用直接 SQL 查询。

    【讨论】:

    • 不是反对你的人 - 尽管我当然不同意动态 SQL 比通用解决方案更可取。
    • @Adam:我没有说它更可取。但我已经多次走这条路了。你为了完成你的任务而与语言抗争。我只是建议实际上这可能是错误的方法。
    • 是的 - 很公平。如果他不能像我建议的那样在其中获得接口,那么一些 SQL 可能会比 EF 大师建议的任何巫术更好。 +1
    • @Adam:谢谢。我把它改写得更好一点,缓和了我的情绪:)
    • 你可能是对的,但他的用例非常简单,就像手卷sql一样高效。
    【解决方案3】:

    怎么样

        public T GetResult<T>(int id, string typeName) {
            AccrualTrackingEntities db = new AccrualTrackingEntities();
            var result = db.CreateQuery<T>(String.Format("[{0}]", typeName));
    
            var param = Expression.Parameter(typeof(T));
    
            var lambda = Expression.Lambda<Func<T, bool>>(
                Expression.Equal(
                    Expression.Property(param, "TypeID"),
                    Expression.Constant(id)),
                param);
    
            return result.Single(lambda);
        }
    

    我想手动将表达式树串在一起并不像我想象的那么难。

    【讨论】:

    • 您能确定来自T 的类型名称并消除一个参数吗?
    • 也许 - typeof(T).Name 将返回(以防万一)“Invoice”,而 EF 期待 ObjectSet 的名称,即“Invoices”如果所有 您的 类型可以通过添加 S 来正确复数,那么您应该可以。但是请注意,如果您有一个 Person 类型的实体,则集合名称可能是 People。
    • 在这种情况下,您可以使用 System.Data.Entity.Design.PluralizationServices.PluralizationService。这是 EF 用来创建您的类型的复数的。真的没那么重要,但总的来说我真的不喜欢魔术弦。
    【解决方案4】:

    考虑到调用此方法时的情况...大概是这样的:

    object obj = GetObject(257, "Type1");
    

    我想不出办法让返回值的类型更具体,因为 EF 中的对象没有公共基类,它们也没有实现公共接口。当然,您可以让它们实现这样的接口(正如 Adam 建议的那样,尽管目的不同),然后像这样重写您的方法:

    public IMyInterface GetObject(int id, string typeName) {
        switch(typeName) {
            case "Type1":
                return (IMyInterface)db.Type1s.SingleOrDefault(t => t.TypeID == id);
            case "Type2":
                return (IMyInterface)db.Type2.SingleOrDefault(t => t.TypeID == id);
            default:
                return null;
        }
    }
    

    那么您的调用代码将如下所示:

    IMyInterface intf = GetObject(257, "Type1");
    intf.DoSomethingHelpful();
    

    当然,我对你的调用代码的猜测可能有点离谱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多