0
votes

I am working with VS2010, .NET 4.0, Entity Framework 4, and POCO entities. I am trying to add and remove child entities from a parent. I have a many-to-many relationship between [User] and [Companies]. So I have the following entity:

// Objects created by POCO template generator
public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public ICollection<Company> Companies { get; set; }
}
public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<User> Users { get; set; }
}

At this point in the code, the User exists but has ZERO companies. What I am trying to do is add a new child Company to the User. This code DOES save the Company but it is also creating a duplicate User parent.

public UserRepository
{
    internal ObjectContextEntities _dbContext = new ObjectContextEntities();
    public User Save(User pocoObject)
    {
        // Load the existing User which has no companies
        var loadedEntity = _dbContext.Users.Where(m => m.Id == pocoObject.Id).FirstOrDefault();

        // Add the new company from a POCO object
        loadedEntity.Companies.Add(pocoObject.Companies.Last());

        _dbContext.SaveChanges();
    }
}

How should I be adding child entities? (Without creating a duplicate relationship?) ... Also is there a simple way to update those children when performing "ApplyCurrentValues()" on the parent User?

2
It should work. Did you omit something in your code snippets? IEnumerable<T> does not have an Add method and your Save method would not compile because of this and because you don't return a User. I guess, this is not your "real" code, is it? - Slauma
Sorry, the POCO generator creates ICollections, which I fixed in my snippet. Btw, the line pocoObject.Companies.Last() is a POCO object, and not a tracked entity. - Nexxas
OK, I see. Just to make sure I understand: You want to insert a new company to the database (pocoObject.Companies.Last() is a new company, not yet existing in the DB, right?) and create a relationship between the existing user and this new company, right? - Slauma
Yes, that is correct. I want to INSERT the new Company into the database, but have it belong to the EXISTING User. - Nexxas
Can you make a little test: Create another context _dbContext2 in your Save method and replace the two _dbContext in your code by _dbContext2. Execute in debugger and watch the database tables directly after _dbContext2.SaveChanges(). If this should work (no user duplication) then you know at least that something else happens with your _dbContext instance which causes the duplication. - Slauma

2 Answers

1
votes

This code does work and does not create duplicate users.

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public ICollection<Company> Companies { get; set; }

    public User()
    {
        Companies = new List<Company>();
    }
}

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

public class POCOEntitiesContext : ObjectContext
{
    private ObjectSet<User> users;
    public ObjectSet<User> Users
    {
        get { return users; }
    }

    private ObjectSet<Company> companies;
    public ObjectSet<Company> Companies
    {
        get { return companies; }
    }

    public POCOEntitiesContext() : base("name=POCOEntities", "POCOEntitiesContainer")
    {
        users = CreateObjectSet<User>();
        companies = CreateObjectSet<Company>();
    }
}

using (var ctx = new POCOEntitiesContext())
{
    var loadedUser = ctx.Users.Where(u => u.Username == "Peri").First();
    loadedUser.Companies.Add(new Company() { Name = "New Company" });
    ctx.SaveChanges();
}
0
votes

I tried a more simplified approach and I figured it out:

    var newCompany = pocoObject.Companies.Last();
    newCompany.Users = null;
    loadedUser.Companies.Add(newCompany);

It turns out because there was a reference to the parent INSIDE the child, it was propagating up and causing a new parent to be created. So from a POCO standpoint, I had to remove the parent and keep it a very simple object. (Or I could have just removed the Child's Parent reference in the edmx). But even this makes my life easier:

    loadedUser.Companies.Add(new Company() { Name = "New Company" });