You code seems to not doing what it is supposed to do.
Assume the following implementation (using the ResetLazy
)
Customer and Order
namespace Entities
{
public class Customer
{
public int Id { get; set; }
public ResetLazy<List<Entities.Order>> Orders {get;set;}
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
}
Simulated database
public class TheDatabase
{
public TheDatabase()
{
customers.Add(new Entities.Customer { Id = 1 });
orders.Add(new Entities.Order { Id = 1, CustomerId = 1 });
orders.Add(new Entities.Order { Id = 2, CustomerId = 1 });
orders.Add(new Entities.Order { Id = 3, CustomerId = 1 });
customers.Add(new Entities.Customer { Id = 2 });
customers.Add(new Entities.Customer { Id = 3 });
orders.Add(new Entities.Order { Id = 4, CustomerId = 3 });
orders.Add(new Entities.Order { Id = 5, CustomerId = 3 });
}
private List<Entities.Customer> customers = new List<Entities.Customer>();
private List<Entities.Order> orders = new List<Entities.Order>();
public List<Entities.Customer> GetCustomersByIds(IEnumerable<int> ids)
{
return customers.Where(c => ids.Contains(c.Id)).ToList();
}
public IEnumerable<Entities.Order> GetOrdersByCustomerIds(IEnumerable<int> ids)
{
return orders.Where(c => IsContained(c.CustomerId, ids));
}
private bool IsContained(int id, IEnumerable<int> ids)
{
foreach (int currentId in ids)
{
if (id == currentId) { return true; }
}
return false;
}
}
And the class containing your methods
class Program
{
static void Main(string[] args)
{
Program p = new Program();
IEnumerable<int> ids = new List<int>() { 1, 2, 3 };
List<Entities.Customer> customers = p.GetCustomersByIds(ids);
int customerId = 1;
List<Entities.Order> orders = new List<Entities.Order>(customers.Where(c => c.Id == customerId).First().Orders.Value);
System.Diagnostics.Debug.Assert(orders[0].CustomerId == customerId);
}
TheDatabase db;
private Program()
{
db = new TheDatabase();
}
public List<Entities.Customer> GetCustomersByIds(IEnumerable<int> ids)
{
var customers = db.GetCustomersByIds(ids);
foreach (var customer in customers)
{
customer.Orders = new ResetLazy<List<Entities.Order>>(() =>
GetOrdersByCustomersLazy(customers, customer.Id));
}
return customers;
}
protected List<Entities.Order> GetOrdersByCustomersLazy(
List<Entities.Customer> customers,
int customerId)
{
var orders = db.GetOrdersByCustomerIds(
customers.Select(customer => customer.Id).AsEnumerable());
foreach (var customer in customers)
{
customer.Orders = new ResetLazy<List<Entities.Order>>(() =>
{
customer.Orders = new ResetLazy<List<Entities.Order>>(() =>
GetOrdersByCustomersLazy(customers, customer.Id));
return orders.Where(order => order.CustomerId == customer.Id).ToList();
});
}
return customers.FirstOrDefault(customer => customer.Id == customerId).Orders.Value;
}
}
The Debug.Assert()
method signals the wrong id.
Fixing
By adding a setter to ResetLazy.Value
like
set
{
if (mode != LazyThreadSafetyMode.None)
{
lock (syncLock)
{
this.box = new Box(value);
}
}
else
{
this.box = new Box(value);
}
}
and changing the GetOrdersByCustomersLazy()
method to
protected List<Entities.Order> GetOrdersByCustomersLazy(
List<Entities.Customer> customers,
int customerId)
{
var orders = db.GetOrdersByCustomerIds(
customers.Select(customer => customer.Id).AsEnumerable());
foreach (var customer in customers)
{
customer.Orders.Value = orders.Where(o => o.CustomerId == customer.Id).ToList();
}
return customers.FirstOrDefault(customer => customer.Id == customerId).Orders.Value;
}
The following runs as expected
Program p = new Program();
IEnumerable<int> ids = new List<int>() { 1, 2, 3 };
List<Entities.Customer> customers = p.GetCustomersByIds(ids);
int customerId = 1;
List<Entities.Order> orders = new List<Entities.Order>(customers.Where(c => c.Id == customerId).First().Orders.Value);
System.Diagnostics.Debug.Assert(orders.Count==3 && orders[0].CustomerId == customerId);
customerId = 2;
orders = new List<Entities.Order>(customers.Where(c => c.Id == customerId).First().Orders.Value);
System.Diagnostics.Debug.Assert(orders.Count==0);
customerId = 3;
orders = new List<Entities.Order>(customers.Where(c => c.Id == customerId).First().Orders.Value);
System.Diagnostics.Debug.Assert(orders.Count == 2 && orders[0].CustomerId == customerId);
You shouldn't shorten names of variables. The advantage of typing less is reduced by the lack of readability.
A call to the linq Select()
method returns an IEnumerable
so a call to AsEnumerable()
is not needed.