1

I'm writing some BLL code to sit on top of Entity framework (DAL classes generated with DBContext but that doesn't matter for this question). Here's one of my routines:

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

So when I call it I pass a CustID, an optinal list of Entities I want included -such as "Orders", and "OrderDetails":

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

It works fine but I don't like calling it with a list or array of strings - I'd like to get strong typing so the IDE can assist.

I could receive a list of types by declaring it like this:

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

and get the class name as a string for the includes to work, but then the caller has to use typeofs like this:

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

which is not the end of the world, but this causes problems because OrderDetails is actually a navigation property from Orders, and the include needs to be called Orders.OrderDetails, and I'd have to have the code poke around to find which entity OrderDetails in the child of and still generate the string.

What I really want is a strongly typed list of entities to pass as includes in the same format EF wants them as includes but I think I am SOL.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
RBrowning99
  • 411
  • 2
  • 9
  • 21
  • It'd be a tough ask to do it by type. What if Customer has two properties that match the "Order" type? eg Customer.OpenOrders and Customer.CompletedOrders, both of type List. – Matt Hamilton Dec 17 '12 at 03:59
  • You could use an enum. That way you can control the list of values. Using types directly can put you in a position where someone puts in a type which is not even an Entity. This can lead to some complex argument validation scenarios. – Elad Lachmi Dec 17 '12 at 04:01
  • Matt - I missed the fact that you can now use a Lambda with the Include - so that's the obvious answer I think. – RBrowning99 Dec 17 '12 at 04:20
  • Don't go mistaking this method for one that belongs in the BLL, though! – Kieren Johnstone Dec 17 '12 at 07:32

2 Answers2

1

Assuming your EF model has relationships maintained Why not use a Custom Get Routine that takes a Lambda. Based on your sample, you get a "customer" back.

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();

You the call the Generic Get routine for Any sets on you context,

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

The Virtual navigation properties are very useful and flexible.

phil soady
  • 11,043
  • 5
  • 50
  • 95
  • HI,Thanks for the comment. I understand what you are saying and I do have such routines - but I think the issue is I want lazy loading disabled so I have to explicitly list the include entities, no? I'm willing to learn...thanks Ray – RBrowning99 Dec 17 '12 at 15:33
  • Context.Configuration.LazyLoadingEnabled = true; // false ? if you want to know more about eager loading... http://stackoverflow.com/questions/6042023/entity-framework-4-1-default-eager-loading – phil soady Dec 17 '12 at 15:40
  • Hi, Thanks for this. I know how to turn off lazy loading - what I'm missing is how your response helps with a list of includes. If lazy loading is off, I understand it's my responsibility to list the includes I want. I don't want to list those as strings and as I commented above I realized can use a lambda - does your suggestion offer anything I am missing? Thanks Ray – RBrowning99 Dec 17 '12 at 17:50
  • I Guess Not, Sorry. If you all that is possible with .Where.Select(new .Where...) – phil soady Dec 17 '12 at 20:14
0

Determining which entities to include in the query should not be a task for anything other than the BLL. If the BLL takes a property or multiple properties which refer to the structure of the data store, then you're saying whatever calls the BLL needs to know about the internal structure of the data store. Edit: not being clear enough. It's plain wrong to do this.

IMO you should create a separate method for each use case - otherwise your BLL is just a helper method for the DAL, and has no responsibility to separation of concerns.

It's a major issue with the Entity Framework - MS make it seem as if you should put your queries together at whatever point you like, and use and keep the entities alive wherever you like too. Makes it very difficult to see the light indeed.

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • Kieren, Let's take an example. Some clients of this BLL might just need a customer. Others might need a customer and orders. Etc. Are you suggesting a separate method for each one? In the real world, and in the model I am working with, for example, I have 30+ linked entities. A separate method for each combination of entities would be overwhelming I think. I'm willing to listen to alternative arguments. Best Ray – RBrowning99 Dec 17 '12 at 15:34
  • Think of the BLL as implementing a contract. A contact isn't worth having if you pass in a whole strategy - as it stands you're looking at "`GetStuff()`". That's not a contract, that's deferring any good design and thought until a later point (when you call the method). If you have 30 different use cases/stories/ways your app legitimately needs to get customer info, then you need different methods. I suggest: don't make the BLL generic, have methods for each of the jobs/tasks that are required of it. Imagine the BLL is an API, as specific as poss, to write a frontend. – Kieren Johnstone Dec 17 '12 at 15:56
  • Kieren, I take your point - and the BLL is not generic - only part of it. The CRUD stuff is generic - and I map between domain objects and DAL objects. A partial class lets me write validation and add custom methods - but the CRUD operations are the same in every entity and I'm not about hand code all these methods. Been there before and it's a PITA when the structure changes. I'm auto generating the base BLL classes with automatic CRUD and mapping from a T4 template. Best Ray – RBrowning99 Dec 17 '12 at 18:24