Bigeyes Bigeyes - 1 year ago 210
C# Question

Generate and auto increment the Id in Entity Framework database first

I have a table

CampaignLanguage
. The primary key is Id. It should be auto increment.
So I have the code:

public partial class CampaignLanguage
{
public CampaignLanguage()
{
this.CampaignLanguageQuestions = new HashSet<CampaignLanguageQuestion>();
}

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }


Then in the controller, I want to save the generated object.

[HttpPost]
public ActionResult Save(int clientId, int campaignId)
{
var campaign = CampaignService.GetCampaignById(campaignId);
var campaignLanguage = campaign.CampaignLanguages.Where(x => x.CampaignId == campaignId).FirstOrDefault();
if (campaignLanguage != null)
{
campaignLanguage.WelcomeMessage = message;
CampaignService.Save(campaignLanguage);
}
else
{
campaignLanguage = new CampaignLanguage();
campaignLanguage.Id = 1;

CampaignService.Save(campaignLanguage);
}
return Redirect("/Campaign/Index/" + clientId);
}


However, I get the error.


{"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."}


I don't want to change my CampaignService.Save method. So how to fix it?

EDIT

public void Save(CampaignLanguage campaignLanguage)
{
_campaignLanguageRepository.Update(campaignLanguage);
_unitOfWork.Commit();
}


EDIT 1

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

Answer Source

You should be calling Add instead of Update as this is a new instance you want to insert into the data store. Your Save method should check if the primary (auto incremented key) has a value greater than 0 to see if it is new or not. Alternatively you can also see if it is already attached. There is also no need to call Update, setting the entity to state modified does nothing except ensure that all properties will be written back to the DB but the DbContext implements change tracking on entities so this will already happen (unless you are working in a detached state).

public void Save(CampaignLanguage campaignLanguage)
{
    if(campaignLanguage.Id == 0)
        _campaignLanguageRepository.Add(campaignLanguage);
    else
        _campaignLanguageRepository.Update(campaignLanguage);

    _unitOfWork.Commit();
}

On a side note: The type DbContext already implements a Unit of Work pattern and DbSet<T> is an implementation of a Repository pattern. There should not be any need to add another customer Unit of work and repository pattern around EF, you are just creating a whole abstraction layer for no reason that will problems with readability as well as issues later when you want to perform more complex operations like joining multiple tables together in a query.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download