开发者

What's the NHibernate session.Load equivalent in Entity Framework?

What's the following NHibernate lazy loading equivalent to Entity Framework?

product.Categories.Add(s.Load<Category>(c开发者_如何学JAVAat));

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


There is no equivalent at the moment.

You can try this however, assuming you won't make any changes to the category.

Entity Framework 4.0:

Category cat = new Category();
cat.Id = i;
context.Attach("Categories", cat);
product.Categories.Add(cat);

Entity Framework 4.1:

Category cat = new Category();
cat.Id = i;
context.Categories.Attach(cat);
product.Categories.Add(cat);

MSDN link

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜