Question

I've spent the past 3 hours scouring the Internet and need better ideas how to achieve what I need. I've entity relations as follows (note: relation, not the actual domain)

class Person
{
    int Id {get;set;}
    string Name {Get;set;}
    virtual DbSet<Order> Orders {get;set;}
}

class Order
{
    int OrderId {get;set;}
    Person Person {get;set;}
    virtual DbSet<Item> Items {get;set;}
}

class Item
{
    int ItemId{get;set;}
    Order Order {get;set;}
}

What I need to do is to query for these from the database and store them into a Dictionary which in turn is stored in the cache. I chose to store as dictionary because the program needs to regularly perform fetch items by Person Name

Dictionary<string, Item>

Here are what I've done so far.

1) Basic Linq 2 SQL. The problem with this is the dictionary values are created as proxies and causes the program to fail when the Item dictionary is traversed after loading from cache because the ObjectContext is closed.

using(var context = new myContext(dbFactory.Create(), contextOwnsConnection: true))
{
var itemLookup = context.Items
             .Include(p=>p.Order.Person)
            .AsNoTracking()
            .GroupBy(p => p.Order.Person.Name)
            .ToDictionary(key=>key.Key, val=> val.ToList());
}

2) Disable proxy creation. I get what I want from the list, but the nested entities (Person, Order) are not set (i.e. Item.Order = null)

context.Configuration.LazyLoadingEnabled = false;
context.Configuration.ProxyCreationEnabled = false;
var itemLookup = context.Items
             .Include(p=>p.Order.Person)
            .AsNoTracking()
            .GroupBy(p => p.Order.Person.Name)
            .ToDictionary(key=>key.Key, val=> val.ToList());

I've tried a few other things like including .Include("Order.Person"), GroupJoin (which I feel is too difficult to read). Now, I know I can address this with two other options:

1) Load the three entities as dictionary (with proper filtering for each, ofcourse) and set the relation in code.

2) Use Dapper as I've had more success with it. The reason I'm not opting for this one is that my team is more familiar working with EF.

Are there any other ways that I can achieve what I need using EF?

Thanks

Was it helpful?

Solution

Sadly, I had to settle with manually building the relationship of objects in code. I'm sure there's a way to make this less painful, hopefully someone can come along and give the pill for this.

var personItemDict = new Dictionary<string, Item>();
var persons = context.Persons.Where(<condition>).ToDictionary(k=>k.Id, v=>v);
var orders = context.Orders.Where(<condition>).ToDictionary(k=>k.OrderId, v=>v);
var items = context.Items.Where(condition).ToList();

foreach(var item in items)
{
    item.Order = orders[item.OrderId];
    item.Order.Person = persons[item.Order.PersonId];

    // Add to dictionary
    if(false == personItemDict.ContainsKey(item.Order.Person.Name))
    {
        personItemDict.Add(
             item.Order.Person.Name,
             new List<Items>());
    }

    personItemDict[item.Order.Person.Name].Add(item);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top