What's the following NHibernate lazy loading equivalent to Entity Framework?
product.Categories.Add(s.Load<Category>(cat));
I tried this, but it read the Category table from the database:
product.Categories.Add(db.Categories.Find(cat));
There is no equivalent and there will probably never be because of a fundamental design flaw in how EF does lazy-loading.
I asked your exact question a while ago in MS' forums: http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/fccfcf68-2b53-407f-9a87-a32426db6f36
While Entity Framework doesn't have an exact equivalent to the Load() method, it does provide the ability to persist a new association without first retrieving an entity or exposing foreign key properties (i.e. arguably the most common use of NHibernate's Load method).
The following extension methods either return an entity already tracked or returns a newly attached entity which can then be used to save new associations:
public static class EntityFrameworkExtensions
{
// Loads when the Id property is always "Id" based on derived types of EntityBase<TId>
public static TEntity LoadEntity<TEntity,TId>(this DbContext context, TId id) where TEntity : EntityBase<TId>, new()
{
var entity = context.ChangeTracker.Entries<TEntity>().SingleOrDefault(e => e.Entity.Id.Equals(id))?.Entity;
if (entity == null)
{
entity = new TEntity { Id = id };
context.Set<TEntity>().Attach(entity);
}
return entity;
}
// Loads when you're dealing with a composite key and need to specify both how to identify the key and how to assign if attaching a newly created entity.
public static TEntity LoadEntity<TEntity>(this DbContext context, Func<TEntity, bool> predicate, Action<TEntity> idAssignmentAction) where TEntity : class, new()
{
var entity = context.ChangeTracker.Entries<TEntity>().SingleOrDefault(e => predicate(e.Entity))?.Entity;
if (entity == null)
{
entity = new TEntity();
idAssignmentAction(entity);
context.Set<TEntity>().Attach(entity);
}
return entity;
}
}
// Loads by allowing you to specify an expression identifying the primary key property
public static TEntity LoadEntity<TEntity, TIdProperty>(this DbContext context,
Expression<Func<TEntity, TIdProperty>> idExpression, TIdProperty id) where TEntity : class, new()
{
var parameterExpression = Expression.Parameter(typeof(DbEntityEntry<TEntity>), "ent");
Expression entityProperty = Expression.Property(parameterExpression, "Entity");
var keyValue = Expression.Invoke(idExpression, entityProperty);
var pkValue = Expression.Constant(id, typeof(TIdProperty));
Expression equalsExpression = Expression.Equal(keyValue, pkValue);
var lambda = Expression.Lambda<Func<DbEntityEntry<TEntity>, bool>>(equalsExpression, parameterExpression);
var lambdaC = lambda.Compile();
var entity = context.ChangeTracker.Entries<TEntity>().SingleOrDefault(lambdaC)?.Entity;
if (entity == null)
{
entity = new TEntity();
var valueParameterExpression = Expression.Parameter(typeof(object));
var targetExpression = idExpression.Body is UnaryExpression
? ((UnaryExpression) idExpression.Body).Operand
: idExpression.Body;
var assign = Expression.Lambda<Action<TEntity, object>>
(
Expression.Assign(targetExpression,
Expression.Convert(valueParameterExpression, targetExpression.Type)),
idExpression.Parameters.Single(),
valueParameterExpression
);
assign.Compile().Invoke(entity, id);
context.Set<TEntity>().Attach(entity);
}
return entity;
}
Example usage:
var account1 = _dbContext.LoadEntity<Account, int>(request.AccountId);
var account2 = _dbContext.LoadEntity<AccountWithComposite>(a => a.X == 1 && a.Y == 2, a => { a.X = 1; a.Y = 2; });
var account3 = _dbContext.LoadEntity<Account, int>(a => a.AccountId, request.AccountId);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With