开发者

How to use a string as a primary key in MVC 3 Entity Framework 4.1 Code First?

I'm using the latest and greatest Entity Framework Code First and I'm running into a scenario where I want one of my classes to use a string for the primary key. I had to manually add the key to the Create View (by default it treats it like an identity). However, when I try to create a new MyAccount, I get the error below. I'm using the MVC Scaffolder Repository pattern to build the MyAccountController. Your wisdom I seek with great appreciation.

Model:

public class MyAccount 
{
    [Key, Required, MaxLength(80), Display(Name = "User name")]   
    public string UserName { get; set; }

    [Required, DataType(DataType.EmailAddress), MaxLength(100), Display(Name = "Email address")]   
    public string Email { get; set; } 
}

View:

<% using (Html.BeginForm()) { %>
    <%: Html.ValidationSummary(true) %>
    <legend>MyAccount</legend>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.UserName) %>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(model => model.UserName) %>
            <%: Html.ValidationMessageFor(model => model.UserName)%>
        </div>
        <%: Html.Partial("CreateOrEdit", Model) %>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
<% } %>

Controller:

    //
    // GET: /MyAccount/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /MyAccount/Create

    [HttpPost]
    public ActionResult Create(MyAccount myaccount)
    {
        if (ModelState.IsValid) {
            myaccountRepository.InsertOrUpdate(myaccount);
            myaccountRepository.Save();
            return RedirectToAction("Index");
        } else {
            return View();
        }
    }

Repository:

public class MyAccountRepository : IMyAccountRepository
{
    Par4ScoreContext context = n开发者_开发百科ew Par4ScoreContext();

    public IQueryable<MyAccount> All
    {
        get { return context.MyAccounts; }
    }

    public IQueryable<MyAccount> AllIncluding(params Expression<Func<MyAccount, object>>[] includeProperties)
    {
        IQueryable<MyAccount> query = context.MyAccounts;
        foreach (var includeProperty in includeProperties) {
            query = query.Include(includeProperty);
        }
        return query;
    }

    public MyAccount Find(string id)
    {
        return context.MyAccounts.Find(id);
    }

    public void InsertOrUpdate(MyAccount myaccount)
    {
        if (myaccount.UserName == default(string)) {
            // New entity
            context.MyAccounts.Add(myaccount);
        } else {
            // Existing entity
            context.Entry(myaccount).State = EntityState.Modified;
        }
    }

    public void Delete(string id)
    {
        var myaccount = context.MyAccounts.Find(id);
        context.MyAccounts.Remove(myaccount);
    }

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

public interface IMyAccountRepository
{
    IQueryable<PlayerAccount> All { get; }
    IQueryable<PlayerAccount> AllIncluding(params Expression<Func<MyAccount, object>>[] includeProperties);
    MyAccount Find(string id);
    void InsertOrUpdate(MyAccount playeraccount);
    void Delete(string id);
    void Save();
}

Error in MyAccountRepository.Save():

System.Data.Entity.Infrastructure.DbUpdateConcurrencyException was unhandled by user code:  
"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."
StackTrace:
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Models.MyAccountRepository.Save() 

....

InnerException: System.Data.OptimisticConcurrencyException
Message=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.
Source=System.Data.Entity
StackTrace:
    at System.Data.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected, UpdateCommand source)
    at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
    at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
    at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
    at System.Data.Entity.Internal.InternalContext.SaveChanges()


Since MVC model binder will assign an empty string to UserName you can check whether its new or not by using string.IsNulOrEmpty(playeraccount.UserName). You can use IsNullOrWhiteSpace if you treat spaces as empty.

public void InsertOrUpdate(MyAccount myaccount)
{
    if (string.IsNulOrEmpty(myaccount.UserName)) {
        // New entity
        context.MyAccounts.Add(myaccount);
    } else {
        // Existing entity
        context.Entry(myaccount).State = EntityState.Modified;
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜