views:

86

answers:

2

I am currently working on my own version of membership using Entity Framework 4.0 and POCO.

After readying Scotts Gu blog post I decided to use conventions as much as possible.

So far I have a class called User:

public class User
{
    [System.ComponentModel.DataAnnotations.Key]
    public int UserId { get; set; }

    [System.ComponentModel.DataAnnotations.StringLength(60)] 
    public string UserName { get; set; }

    public string Password { get; set; }

    [System.ComponentModel.DataAnnotations.ConcurrencyCheck]
    public string Email { get; set; }

    [System.ComponentModel.DataAnnotations.Timestamp]
    public byte[] Timestamp { get; set; }

    public ICollection<Role> Roles { get; set; }
}

and a class called Role

public class Role
{
    [System.ComponentModel.DataAnnotations.Key]
    public int RoleId { get; set; }

    [System.ComponentModel.DataAnnotations.StringLength(50)]
    public string RoleName { get; set; }

    [System.ComponentModel.DataAnnotations.StringLength(300)]
    public string RoleDescription { get; set; }

    public ICollection<User> Users { get; set; }
}

I also implement DbContext like this :

public class BackboneDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }
}

Then based on what Scott suggested I created a Initializer class inheriting from RecreateDatabaseIfModelChanges.

Then in that class I add some dummy items like this:

    protected override void Seed(BackboneDbContext context)
    {
        var roles = new List<Role>
        {
            new Role
                {
                    RoleId = 0,
                    RoleName = "User",
                    RoleDescription = "This role belong to normal users.",
                }

        };

        roles.ForEach(r => context.Roles.Add(r));

        var users = new List<User>
        {
            new User  {UserId = 1, 
                       UserName = "Elham", 
                       Email = "[email protected]", 
                       Password = "xyz",
                       Roles = new List<Role>
                                   {
                                      roles[0]
                                   }

                       }

        };

        users.ForEach(u => context.Users.Add(u));
    }

I hope it make sense up to here. If not, basically the above code populate the tables with dummy data if database schema changes.

so far everything is absolutely great. I get the following tables:

Roles, Roles_Users and Users

they all have the info I need, but the problem is when I use the following LINQ query in my Repository class to get all the USers:

    public IQueryable<User> GetAllUsers()
    {
        IQueryable<User> allUsers = from u in _backboneDbContext.Users select u;

        return allUsers;
    }

now if I check allUsers before passing it to View, I get my users but the Role is set to 'Null'

I don't know why... Any Ideas ? Thank you.

+2  A: 

You have to add a [System.ComponentModel.DataAnnotations.Association] attribute. For example:

public class User
{
    // [...]

    [System.ComponentModel.DataAnnotations.Association("User_Roles", "UserId", "RoleId")]
    public ICollection<Role> Roles { get; set; }
}

public class Role
{
    // [...]

    [System.ComponentModel.DataAnnotations.Association("Role_Users", "RoleId", "UserId")]
    public ICollection<User> Users { get; set; }
}

If the association is intended to be bi-directional, you must add this attribute on both the User.Roles and the Role.Users properties.

Timwi
Thanks for the answer Timwi,I have done that but unfortunately its still not working ! I can see the association work when I add those test data, because in the table Roles_Users I get association. but when I read it like before I get null for the Role property !You mentioned that for Users property I should add that association attribute and you used "Role_Users" for the first parameter. is that the name of the table or just a name. Because I don't see that table exist in my tables list, the only association table I see there is : Roles_Users?
Raha
I believe it is just a name. In Microsoft SQL Server, it is the foreign-key constraint between the tables that will get this name.
Timwi
Timwi, I made the properties virtual as Wubbsy suggested and its now working.Thanks for your answer ! :)
Raha
+1  A: 

Try making your ICollection properties virtual. This allows EF to do lazy loading of the relationship. Alteratively, look into using the Include method on the query to eagerly load related entities.

Wubbsy
Thanks very much that was the correct answer and its now working, I made the properties virtual ! :) I prefer lazy loading....
Raha