7

I have a problem with entity framework in C#. I have 2 entities, User and UserRole. They are bond by relationships User *->1 UserRole

Whenever I use this query in a function:

User user = context.User.Where(i => i.id == id).FirstOrDefault();
return user.UserRole.accessLevel;

The query returns user, but UserRole is null. The User table has roleId which is related to id of UserRole, and the value of roleId when debugging is correct, although UserRole entity is null. This is strange as it never happened before...

I already made sure that my relationships in model and database are correct. I have correct rows added to database.

EDIT:

Sorry, I should've mentioned I use custom testable database controller:

public class DBController : IUnitOfWork
{
    readonly ObjectContext context;
    const string ConnectionStringName = "MarketPlaceDBEntities";

    public DBController()
    {
        var connectionString =
        ConfigurationManager
            .ConnectionStrings[ConnectionStringName]
            .ConnectionString;
        context = new ObjectContext(connectionString);
    }

    public void Commit()
    {
        context.SaveChanges();
    }

    public IObjectSet<Category> Category
    {
        get { return context.CreateObjectSet<Category>(); }
    }
    public IObjectSet<ItemComment> ItemComment 
    {
        get { return context.CreateObjectSet<ItemComment>(); }
    }
    public IObjectSet<ItemRating> ItemRating 
    {
        get { return context.CreateObjectSet<ItemRating>(); }
    }
    public IObjectSet<Item> Item 
    {
        get { return context.CreateObjectSet<Item>(); }
    }
    public IObjectSet<ItemSale> ItemSale 
    {
        get { return context.CreateObjectSet<ItemSale>(); }
    }
    public IObjectSet<ItemScreenshot> ItemScreenshot 
    {
        get { return context.CreateObjectSet<ItemScreenshot>(); }
    }
    public IObjectSet<UserRole> UserRole 
    {
        get { return context.CreateObjectSet<UserRole>(); }
    }
    public IObjectSet<User> User 
    {
        get { return context.CreateObjectSet<User>(); }
    }
}

And I do operations via it. Maybe it has to do something with my prob.

interface IUnitOfWork
{
    IObjectSet<Category> Category { get; }
    IObjectSet<ItemComment> ItemComment { get; }
    IObjectSet<ItemRating> ItemRating { get; }
    IObjectSet<Item> Item { get; }
    IObjectSet<ItemSale> ItemSale { get; }
    IObjectSet<ItemScreenshot> ItemScreenshot { get; }
    IObjectSet<UserRole> UserRole { get; }
    IObjectSet<User> User { get; }
    void Commit();
}

I had this whole thing working before, but don't know why it went wrong..

EDIT2:

Solved! Thanks RicoSuter.

Enabling lazy loading in constructor of my db controller solved the problem. I thought it was already enabled, because it was set to true in database model, but it looks like that when creating a new context, you have to enable it manually again.

public DBController()
{
    var connectionString =
    ConfigurationManager
        .ConnectionStrings[ConnectionStringName]
        .ConnectionString;
    context = new ObjectContext(connectionString);
    context.ContextOptions.LazyLoadingEnabled = true;
}
4
  • Assuming your question is, why doesen't this work? Either there is no UserRole for that roleId or, you need to check the relationships in the model again. Commented Jul 24, 2012 at 10:21
  • Have you specified that the UserRole property on your User class is virtual? Similarly, on your User class you should mark the Users collection (assuming you have one) as virtual. Commented Jul 24, 2012 at 10:24
  • As an aside, you can rewrite your query as User user = context.User.Find(id). Commented Jul 24, 2012 at 10:27
  • context.User somehow does not have Find method... Commented Jul 24, 2012 at 12:09

3 Answers 3

7

try to eagerly load UserRole (join):

context.User.Include("UserRole").Where(i => i.id == id).FirstOrDefault();

or enable lazy loading first:

context.ContextOptions.LazyLoadingEnabled = true;
context.User.Where(i => i.id == id).FirstOrDefault();

otherwise there is no relation to a UserRole in your database...

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

5 Comments

Hello, looks promising. I have seen this recommended to somebody too, but couldn't find how to do that in my case. However, there is no [...].Include method. LazyLoading is enabled in model instantiation. I should've mentioned, I use testable database controller, which implements IUnitOfWork interface. I'll edit my post with details.
Include can be found in class ObjectQuery<TEntity> (ObjectSet<TEntity> : ObjectQuery<TEntity>). This method is required to create better performing SQL queries (join instead of two queries). Eventually you should create your own interface: IMyObjectSet : IObjectSet { void Include(); } which includes this method.
@RicoSuter I totaly agree with this answer and +1 for using .Include and LazyLoadingEnabled
Since I am using custom database controller, I couldn't use Include as in your example, but enabling LazyLoading on instantiation of my controller did solve the problem, thanks
You should consider using Include as it is much faster than lazy loading. Think of a list of entities with a navigation property; if you lazy load every navigation property you will have 1 query for the list and for each item another query. If you use eager loading you only have one query which takes a little bit more time because it contains an SQL join.
0

Try this

User user = context.User.Where(i => i.id == id).FirstOrDefault(); return user==null?null:user.UserRole.accessLevel;

1 Comment

That simply ignores my user role, which is null, I don't want that happening, as I'm using the value of user role.
0

Most simply u can do this:

UserRole user = context.User.Where(i => i.id == id).Select(i => i.UserRole);
return user.accessLevel;

Edit:

Assuming you already have a relation between User and UserRole

User user = context.User.Where(i => i.id == id).FirstOrDefault();
UserRole role = context.UserRole.Where(i => user.Contains(i.id)).FirstOrDefault();
return role.accessLevel;

Assuming you dont have a relation between User and UserRole

int roleid = Convert.ToInt32(context.User.Where(i => i.id == id).Select(i => i.roleid));
UserRole role = context.UserRole.Where(i => i.id == roleid).FirstOrDefault();
return role.accessLevel;

Also if you have relation but cant see UserRole under User than try adding this to your model

public IDisposable User()
{
    YourDataContext context = new YourDataContext();
    Type ct = context.User.GetType();
    return (IDisposable)(ct);
}

2 Comments

Please read my edit. Your solution seems to work, but that ignores entity framework purpose, or at least the thing why I made that DBController class. The strangest thing that it used to work my way before, and I don't remember what I did before it went wrong..
i edited my post too, but so far i couldnt see any association(relation) between User and UserRole in ur model so try these or simply reconsider using @RicoSuter solution.

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.