其他分享
首页 > 其他分享> > 实体框架加载相关实体

实体框架加载相关实体

作者:互联网

我使用的是代码优先的Entity Framework,其基本上下文仅由标准IDbSet集合组成,其中T只是POCO类.就我而言,我已禁用了延迟加载.虽然我的模型类中有“导航属性”,但是我从它们中删除了virtual关键字.

存储库中的“全部获取”方法执行一些自定义筛选,以确保当前用户仅看到他们拥有的数据,除非他们是管理员.我在以与某些记录相关联的管理员身份登录时遇到了一个特殊问题.由于我登录时所使用的实体是在上下文中加载的,因此即使我禁用了延迟加载,已删除虚拟且未使用“包含”或“加载”,结果中与我的配置文件相关联的对象仍具有导航属性自动设置.

这不是我的项目中的代码,仅是一个示例,用以说明我在做什么.它可能存在拼写错误和语法错误.

public class Record
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Owner Owner { get; set; } //No virtual keyword
    public Guid OwnerId { get; set; }
}

public class Owner
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Collection<Record> Records { get; set; } //No virtual keyword
}

public class Context : DbContext
{
    IDbSet<Owner> Owners { get; set; }
    IDbSet<Record> Records { get; set; }
    public static Context Create()
    {
        Context context = new Context();
        context.Configuration.LazyLoadingEnabled = false; //Lazy loading disabled
        return context;
    }
}

public class Repository
{
    private Context Context { get; set; }
    public Owner CurrentOwner { get; private set; }
    public Repository()
    {
        Context = Context.Create();

        //Code here to get the application user and look up an associated "owner"
        //entity if the user is an "owner" (they could just be an administrator)
        //but the GetCurrentOwnerOrNull uses the Context to find the user
        CurrentOwner = GetCurrentOwnerOrNull();
    }

    public IQueryable<Record> GetRecords(bool asAdmin)
    {
        IQueryable<Record> records = Context.Records; //Not including or loading Owner
        if (asAdmin)
        {
           //Verify that the application user is an admin and throw exception otherwise
        }
        else
        {
            if (CurrentOwner == null)
            {
                //Throw a security exception
            }
            records = records.Where(r => r.OwnerId == CurrentOwner.Id);
        }
        return records;
    }
}

同样,上述问题是,如果我以所有者(无论是否是管理员)的身份运行该代码,则我拥有的那些记录将设置Owner属性而不是null.我希望实体框架脱离我的业务,​​而不是自动设置.这会在下游引起问题,尤其是在以管理员和所有者身份运行代码时,因此您会获得一些带有Owner = null的记录和一些带有Owner设置的记录.它很烦人.请让我停下来.

解决方法:

该错误实际上是一个功能.实体框架将自动在同一上下文中关联关联,即使实体彼此独立地加载也是如此.

让我们假设以下内容:

public class Person
{
  public Person()
  {
    this.Pets = new List<Pet>();
  }

  public int Id { get; set; }
  public string Name { get; set; }

  public virtual ICollection<Pet> Pets { get; set; }
}

public class Pet
{
  public int Id { get; set; }
  public string Name { get; set; }
  public int PersonId { get; set; }

  public virtual Person Owner { get; set; }
}

我们还假设它们是正确关联的DB-First或Attributes / Fluent API代码优先.

数据库:

Persons
Id Name
1  Erik Philips

Pets
Id Name PersonId
1  Joe  1

将会发生以下情况:

var pet = DbContext.Pets.FirstOrDefault(id => id == 1);
var person = DbContext.Persons.FirstOrDefault(id => id == 1);

Assert.AreEqual(person.Pets.Count(), 1);
Assert.IsNotNull(pet.Person);
Assert.AreEqual(pet.Person, person);

发生这种情况的原因是,上下文将保留其缓存中的对象.如果您不关心持有这些对象的上下文,则需要使用AsNoTracking().

标签:lazy-loading,c,entity-framework
来源: https://codeday.me/bug/20191029/1958166.html