0

I have a entity like:

public class Doctor : User
{
    public Doctor(string userName, string firstName, string lastName,
        string mobileNumber, string email, Sexes sex, Role myRole, DoctorExpertises expertise)
        : base(userName, firstName, lastName, mobileNumber, email, sex, myRole)
    {
        this.Expertise = expertise;
        this.Results = new List<Result>();
    }

    private Doctor()
    {
        this.Results = new List<Result>();
    }

    public void AddResult(Result result)
    {
        this.Results.Add(result);
    }

    public DoctorExpertises Expertise { get; private set; }

    private ICollection<Result> results;

    public virtual ICollection<Result> Results
    {
        get { return results; }
        private set { results = value; }
    }
}

And I have typical repository like:

public abstract class RepositoryBase<T> where T : class
{
    private DbContext dataContext;
    protected readonly IDbSet<T> dbset;

    protected RepositoryBase(IDatabaseFactory databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory DatabaseFactory
    {
        get;
        private set;
    }

    protected DbContext DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    public virtual void Add(T entity)
    {
        dbset.Add(entity);
    }

    public virtual void Update(T entity)
    {
        dbset.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    }

    public virtual void Delete(T entity)
    {
        dbset.Remove(entity);
    }

    public virtual void Delete(Expression<Func<T, bool>> where)
    {
        IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
        foreach (T obj in objects)
            dbset.Remove(obj);
    }

    public virtual T GetById(long id)
    {
        return dbset.Find(id);
    }

    public virtual T GetById(string id)
    {
        return dbset.Find(id);
    }

    public virtual IEnumerable<T> GetAll()
    {
        return dbset.ToList();
    }

    public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
    {
        return dbset.Where(where).ToList();
    }

    public T Get(Expression<Func<T, bool>> where)
    {
        return dbset.Where(where).FirstOrDefault<T>();
    }
}

And I want lazy load one result from doctor with below test code:

[TestMethod]
public void TestShouldLoadPropertyIfLazyLoaded()
{
    // Act
    Doctor doctor = this.userRepository.Get(u => u.UserName == "soroosh") as Doctor;
    Result result = doctor.Results.FirstOrDefault();

    // Asserts
    Assert.IsNotNull(doctor);
    Assert.IsNotNull(result);
}

Unfortunately it doesn’t work correctly. doctor is not null, but result is null.

If I use eager loading with include method it loads correctly, but I definitely want to use lazy loading.

I have seen this question and other questions like this, but none of them wasn't useful, because all of them use eager loading to solve problem. Eager loading is not suitable for us, because in my main problem it seems eager loading is not possible.

What should I do?

8
  • I'm sorry but I didn't understand what did you said. I say again doctor is not null. thank you :) Commented Nov 15, 2013 at 15:33
  • OK I misunderstood You - sorry for that ;) I deleted the comment ;) Maybe You could try the following: Result result = doctor.Results.ToList().FirstOrDefault(); btw You should conssider splitting this into two separate tests ;) Commented Nov 15, 2013 at 15:45
  • Oh and where does userRepository come from? Are You hiting the database? Commented Nov 15, 2013 at 15:51
  • in initialize method I wrote some code like : this.userRepository = new UserRepository(this.databaseFactory); UserRepository is derived class from BaseRepository. Commented Nov 15, 2013 at 17:44
  • Why would you need lazy loading? Are you sure Result isn't another AR? Commented Nov 15, 2013 at 18:12

2 Answers 2

0

This should just work. People including myself do this daily and it works. I see two possible culprits:

  • the dbcontext factory could possibly create a context where lazy loading is disabled
  • the setter of your Records property is private and the generated proxy entity could just not handle it properly. Just change it to public.

Check both, and focus on the second.

Sign up to request clarification or add additional context in comments.

1 Comment

I would suggest going with protected rather than public, because lazy-loaded properties probably shouldn't have setters stackoverflow.com/a/14774042/150342. Then I'd add a backing field to avoid the "virtual call in constructor" code smell
0

I reckon if you fully define your aggregate boundaries you don't really need to worry about this - you can always eagerly load when loading entities to perform domain operations because your relationships shouldn't cross aggregate boundaries. Your repository should therefore only be able to load and save a single aggregate of a given type, so that the behaviour on that aggregate can be invoked.

Don't get me wrong. You might still want to query your database to put data on the UI, etc., but you could just use a simple tool like LINQ to SQL, Dapper, etc. and whack the data straight out of the database into the UI, skipping all the ORM eager/lazy loading nonsense.

2 Comments

Whacking the data directly from the database into the ui sounds like something that should be avoided at any cost if your code is to survive longer that the first demo. Orm could be nonsene but a properly layered and testable code begs for at least one layer of abstraction behind these two.
What problem is that layer of abstraction trying to solve? And how would tech like EF database-first, L2S or Dapper not be that layer of abstraction? You should be spending effort where it counts - on your domain logic and the invariants and business rules within. That's where the bulk of your tests should be. There's little point testing that you're able to read from a database, and really, how often are you likely to switch to a new rdbms anyway? I'm not saying write awful code with no exception handling etc, it should still be Clean Code, just it's not where the goal of a DDD app lies.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.