【问题标题】:Includes generic type parameters包括泛型类型参数
【发布时间】:2012-12-17 03:55:15
【问题描述】:

我正在编写一些位于实体框架之上的 BLL 代码(使用 DBContext 生成的 DAL 类,但这对于这个问题并不重要)。这是我的日常工作之一:

public static Customer Get(int32 CustID, IEnumerable<string> IncludeEntities = null)
{
}

所以当我调用它时,我会传递一个 CustID,一个我想要包含的实体的可选列表 - 例如“订单”和“订单详细信息”:

Customer customer = CustomerBLLRepository.Get("ALFKI", 
     new[] { "Orders", "Orders.Order_Details"});

它工作得很好,但我不喜欢用字符串列表或数组来调用它——我想获得强类型,以便 IDE 可以提供帮助。

我可以通过这样声明来接收类型列表:

public static void GetTest(Int32 CustID, params Type[] IncludeEntities)
{
}

并获取类名作为包含工作的字符串,但是调用者必须像这样使用 typeofs:

CustomerRepository.GetTest(123, typeof(Order), typeof(OrderDetails));

这不是世界末日,但这会导致问题,因为 OrderDetails 实际上是 Orders 的导航属性,并且包含需要调用 Orders.OrderDetails,我必须让代码四处寻找才能找到子实体 OrderDetails 中的哪个实体仍然生成字符串。

我真正想要的是一个强类型的实体列表,以与 EF 希望它们作为包含相同的格式传递,但我认为我是 SOL。

【问题讨论】:

  • 按类型来做这件事很难。如果客户有两个与“订单”类型匹配的属性怎么办?例如 Customer.OpenOrders 和 Customer.CompletedOrders,都是 List. 类型
  • 你可以使用枚举。这样您就可以控制值列表。直接使用类型可以使您处于有人放入甚至不是实体的类型的位置。这可能会导致一些复杂的参数验证场景。
  • Matt - 我错过了您现在可以将 Lambda 与 Include 一起使用的事实 - 所以我认为这是显而易见的答案。
  • 不过,不要把这种方法误认为是属于 BLL 的方法!

标签: c# entity-framework generics typeof


【解决方案1】:

假设您的 EF 模型保持了关系 为什么不使用采用 Lambda 的自定义获取例程。 根据您的样本,您将获得“客户”。

public class RepositoryCustomer: RepositoryBase<Customer> 
...
...
public class RepositoryEntityBase<T>
   public virtual T Get(Expression<Func<T, bool>> predicate)
       return Context.Set<T>.Where(predicate).FirstOrDefault();

您可以为上下文中的任何集合调用 Generic Get 例程,

var aCustomer = RepositoryCustomer.Get(c=>c.id=="ALFKI" && c.Orders.OrderDetail=="bla")

虚拟导航属性非常有用且灵活。

【讨论】:

  • 您好,感谢您的评论。我明白你在说什么,我确实有这样的例程 - 但我认为问题是我想要禁用延迟加载,所以我必须明确列出包含实体,不是吗?我愿意学习...谢谢雷
  • Context.Configuration.LazyLoadingEnabled = true; // 错误的 ?如果您想了解更多关于预加载的信息...stackoverflow.com/questions/6042023/…
  • 嗨,谢谢。我知道如何关闭延迟加载-我缺少的是您的响应如何帮助包含列表。如果延迟加载关闭,我知道列出我想要的包含是我的责任。我不想将它们列为字符串,正如我在上面评论的那样,我意识到可以使用 lambda - 你的建议是否提供了我所缺少的任何东西?谢谢雷
  • 我猜不是,对不起。如果您可以使用 .Where.Select(new .Where...)
【解决方案2】:

确定要在查询中包含哪些实体不应该是 BLL 以外的任何任务。如果 BLL 采用一个或多个引用数据存储结构的属性,那么您说的是 BLL 需要了解数据存储的内部结构的任何调用。编辑:不够清楚。这样做是完全错误的。

IMO 您应该为每个用例创建一个单独的方法 - 否则您的 BLL 只是 DAL 的辅助方法,不负责关注点分离。

这是 Entity Framework 的一个主要问题 - MS 让您看起来好像应该在您喜欢的任何时候将您的查询放在一起,并在您喜欢的任何地方使用和保持实体活动。确实很难看到光。

【讨论】:

  • 基伦,我们举个例子。这个 BLL 的一些客户可能只需要一个客户。其他人可能需要客户和订单。等等。您是否建议为每个方法使用单独的方法?在现实世界中,在我正在使用的模型中,例如,我有 30 多个链接实体。我认为对每种实体组合使用单独的方法将是压倒性的。我愿意听取其他论点。最佳雷
  • 将 BLL 视为执行合同。如果你传递了一个完整的策略,那么一个联系人就不值得拥有——就目前而言,你正在查看“GetStuff()”。这不是合同,而是将任何好的设计和想法推迟到以后(当您调用该方法时)。如果您有 30 种不同的用例/故事/方式,您的应用程序合法地需要获取客户信息,那么您需要不同的方法。我建议:不要使 BLL 通用,为每个所需的工作/任务提供方法。想象一下,BLL 是一个 API,与 poss 一样具体,用于编写前端。
  • Kieren,我同意你的观点——BLL 不是通用的——只是其中的一部分。 CRUD 的东西是通用的——我在域对象和 DAL 对象之间进行映射。部分类允许我编写验证并添加自定义方法 - 但每个实体中的 CRUD 操作都是相同的,我不是要手动编写所有这些方法。以前去过那里,当结构发生变化时,它是一个 PITA。我使用自动 CRUD 自动生成基本 BLL 类并从 T4 模板映射。最佳雷
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
  • 2017-10-06
  • 1970-01-01
相关资源
最近更新 更多