使用EF LazyLoading初始化属性?

时间:2013-01-27 13:15:25

标签: c# entity-framework lazy-loading lazy-evaluation

更新:我知道我不应该使用DbSet所以我将实现更改为Erenga建议的ICollection

请考虑以下课程:

[Table("Tenant")]
public class Tenant : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    [Key]
    public string Guid { get; set; }
    public virtual ICollection<User> Users { get; set; }
}

[Table("User")]
public class User : IEntity
{
    public int Id { get; set; }

    public string Name { get; set; }
    public string EmailAddress { get; set; }
    public string Password { get; set; }
}

第一个测试创建一个新租户和一个新用户,并将它们存储在适当的表中。

    [Test]
    public void CreateNewUserForNewTenant()
    {
        var user = _applicationContext.Users.Create();
        user.Name = "barney";
        user.EmailAddress = "barney@flinstone.com";

        var tenant = _applicationContext.Tenants.Create();
        tenant.Name = "localhost";
        tenant.Guid = Guid.NewGuid().ToString();

        tenant.Users.Add(user); // NullReferenceException, I expected the EF would LazyLoad the reference to Users?!
        _tenantRepository.Add(tenant);
        _applicationContext.SaveChanges();
    }

此测试将在NullReferenceException上失败,因为属性Users未初始化。

我应该如何更改我依赖于EF提供的LazyLoading的代码?

3 个答案:

答案 0 :(得分:2)

    var tenant = new Tenant
        {
            Name = "localhost",
            Guid = Guid.NewGuid().ToString(),
            Users = new List<User> { user }
        };

答案 1 :(得分:2)

我在这里看到了两个问题。

  1. 正如@SimonWhitehead所提到的,默认情况下,引用类型初始化为null。延迟加载仅适用于EF创建的实体。这些实际上是您的类的子类,包含延迟加载的附加逻辑。

  2. DbSet不是实体支持的集合类型。您需要将类型更改为ICollectionISetIList

  3. 这是一个有效的例子

    [Table("Tenant")]
    public class Tenant : IEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
        [Key]
        public string Guid { get; set; }
        public virtual ICollection<User> Users { get; set; }
    }
    
    [Table("User")]
    public class User : IEntity
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
        public string EmailAddress { get; set; }
        public string Password { get; set; }
    }
    
    [Test]
    public void CreateNewUserForNewTenant()
    {
        var user = _applicationContext.Users.Create();
        user.Name = "barney"; 
        user.EmailAddress = "barney@flinstone.com";
    
        var tenant = _applicationContext.Tenents.Create();
        tenant.Name = "localhost";
        tenant.Guid = Guid.NewGuid().ToString();
    
        tenant.Users = new List<User> { user };
        _tenantRepository.Add(tenant);
        _applicationContext.SaveChanges();
    }
    

答案 2 :(得分:0)

我认为你期待这样的事情(不是线程安全):

[Table("Tenant")]
public class Tenant : IEntity
{
    private DbSet<User> _users;

    public int Id { get; set; }
    public string Name { get; set; }
    [Key]
    public string Guid { get; set; }

    public virtual ICollection<User> Users 
    {
        get 
        {
            if (_users == null)
                _users = new List<Users>();

            return _users;
        }
        set { _users = value; }
    }
}

我确信Lazy<T>课程也可以以某种方式使用,但我对这门课程并不熟悉。