1

I'm trying to figure out why when I insert a JobOffert record into my MS SQL Server Database I'm getting a duplicated record of My Professional that is an attribute of JobOffert, let me show my code:

Here is my controller Post Method:

[HttpPost]
public ActionResult CreateJobOffert(JobOffertModel jobOffert, FormCollection data)
{
    initBusinessObjects();

    Util.Util.ChangeContextInstance(customerBusiness, null, skillBusiness, jobOffertBusiness);

    var allSkills = skillBusiness.GetAllSkills();
    var allProfessionals = professionalBusiness.GetAllElements();
    //Se eu recarregar a mesma página eu tenho que carregar os ViewBags

    if (ModelState.IsValid)
    {
        var customerId = int.Parse(data["customerId"]);
        var professionalId = int.Parse(data["professionalsList"]);

        var customer = customerBusiness.GetById(customerId);
        var professional = professionalBusiness.GetById(professionalId);

        var skillsIds = data["requiredSkills"].Split(',').Select(x => int.Parse(x));

        jobOffert.Skills = allSkills.Where(x => skillsIds.Contains(x.Id)).ToList();
        jobOffert.Customer = customer;

        if (jobOffert.Active)
        {
            jobOffert.Professional = professional;
        }

        jobOffertBusiness.Insert(jobOffert);

        return View("Edit", customer);
    }

    return View("CreateJobOffert", jobOffert);
}

Here I return My Professional by its ID:

public ProfessionalModel GetProfessionalById(int id)
{
    var professional = Context.ProfessionalContext
                                .Include(x => x.UserAccount)
                                .Include(x => x.UserAddress)
                                .Include(x => x.Skills)
                                .Include(x => x.Skills.Select(y => y.Category))
                                .Include(x => x.Tasks)
                                .FirstOrDefault(x => x.Id == id);

    return professional;
}

That's curious because My Customer, another attribute of JobOffert is not duplicated, here I got my customer?

public CustomerModel GetCustomerById(int id)
{
    var customer = Context.CustomerContext
                                .Include(x => x.UserAccount)
                                .Include(x => x.UserAddress)
                                .Include(x => x.JobOfferts)
                                .FirstOrDefault(x => x.Id == id);

    return customer;
}

And this is my JobOffertModel:

public class JobOffertModel
{
    [Key]
    public int Id { get; set; }

    public ProfessionalModel Professional { get; set; }

    [Required]
    public string Description { get; set; }

    [Required]
    [DefaultValue(false)]
    public bool Acepted { get; set; }

    [Required]
    [DefaultValue(true)]
    public bool Active { get; set; }

    public ICollection<SkillModel> Skills { get; set; }

    [Required]
    [Column(TypeName = "DateTime2")]
    public DateTime JobDate { get; set; }

    public virtual CustomerModel Customer { get; set; }
}

Any Idea? How can I fix this and stop to duplicate my professional records?

Thanks!

EDIT

Hi, I got good news, I did it, but the bad news is that I've no idea why it works. I just must to select again my professional, but this time, when I'm one step to store my data, here is my old Insert JobOffert method:

        public void Insert(JobOffertModel jobOffertModel)
        {
            Context.JobOffertContext.Add(jobOffertModel);
            Context.SaveChanges();
        }

And here my new Insert JobOffert method:

        public void Insert(JobOffertModel jobOffertModel)
        {
            var professional = Context.ProfessionalContext.Include(x => x.UserAccount)
                                        .Include(x => x.UserAddress)
                                        .Include(x => x.Skills)
                                        .Include(x => x.Skills.Select(y => y.Category))
                                        .Include(x => x.Tasks)
                                        .FirstOrDefault(x => x.Id == jobOffertModel.Professional.Id);
            jobOffertModel.Professional = professional;

            Context.JobOffertContext.Add(jobOffertModel);
            Context.SaveChanges();
        }

So, now I change my question, why using second approach it works and using the first one it doesn't?

Thanks again!

3
  • If you open developer tools in your browser are you getting duel http requests to the url ? Because the code appears fine to me on first glance. Commented May 6, 2014 at 2:49
  • No that's not my problem, actually I got the solution, but I don't know why it works, I'll edit the post ... Commented May 6, 2014 at 2:59
  • Why does Entity Framework Reinsert Existing Objects into My Database? msdn.microsoft.com/en-us/magazine/dn166926.aspx Commented May 6, 2014 at 9:55

2 Answers 2

1

The crux is that DbSet.Add marks all objects in an object graph as Added that have not yet been attached to the context. Even if an object has a primary key value, EF inserts it and a new PK value is generated.

In your first insert method the professional is not attached to the context that executes the insert. In the second method, it is, because you fetch it right before you set jobOffertModel.Professional.

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

2 Comments

So the correct approach is send only the id to DAO layer, and then find the professional?
I guess so, if by DAO you mean the component that contains the Insert method. By the way, it is useless to get the Professional with all these Includes, as you're only interested in the Professional itself. Another thing is that JobOffertModel could also contain a primitive ProfessionalId property, besides Professional, so you can simply set the id value to establish the association (see foreign key associations).
0

Insert Code 1

Here you do not do any validation and simply add the data to the JobOffertContext table. So each new irrespective of the values present in the db each and every time a new record gets added to db.

public void Insert(JobOffertModel jobOffertModel)
{
    Context.JobOffertContext.Add(jobOffertModel);
    Context.SaveChanges();
}

Insert Code 2

Here you first take out the already inserted data using FirstOrDefault(); and then update the Professional field if the record is found and then save it. Hence now you don't the duplicate record because no new record has been inserted instead it has been updated. if record not present the FirstOrDefault will return null and jobOffertModel.Professional will get a value of null and will be inserted to the db.

public void Insert(JobOffertModel jobOffertModel)
{
    var professional = Context.ProfessionalContext.Include(x => x.UserAccount)
                                .Include(x => x.UserAddress)
                                .Include(x => x.Skills)
                                .Include(x => x.Skills.Select(y => y.Category))
                                .Include(x => x.Tasks)
                                .FirstOrDefault(x => x.Id == jobOffertModel.Professional.Id);

    jobOffertModel.Professional = professional;

    Context.JobOffertContext.Add(jobOffertModel);
    Context.SaveChanges();
}

2 Comments

Okay, but my method GetById calls a the method GetProfessionalById, that is the same code used at second approach, the difference is one method called at controller and another called at DAO layer. It must to work calling from controller or just at DAO?
I cannot comment on this without seeing your method

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.