实体框架更新实体与查找表

时间:2015-04-13 09:20:53

标签: c# asp.net-mvc entity-framework

所以, 我已经构建了一个存储库/服务应用程序,我已成功使用了一段时间。 我已经开始了一个新项目,在这个项目中,我有一个查找表附加到我的一个模型/实体。 该模型如下所示:

public class Team
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Sport { get; set; }

    public IList<Colour> Colours { get; set; }
}

我还有一个绑定的ViewModel,如下所示:

public class TeamBindingViewModel
{
    public int Id { get; set; }
    [Required] public string Name { get; set; }
    [Required] public string Sport { get; set; }

    public IList<ColourBindingViewModel> Colours { get; set; }
}

public class ColourBindingViewModel
{
    public int Id { get; set; }
    [Required] public string Name { get; set; }
    [Required] public string Hex { get; set; }
}

在我的 dbContext 类中,我设置了这个:

public class DatabaseContext : DbContext
{

    // Define our tables
    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }

    public DbSet<Colour> Colours { get; set; }
    public DbSet<Team> Teams { get; set; }

    /// <summary>
    /// static constructor (only gets called once)
    /// </summary>
    static DatabaseContext()
    {

        // Create the database and insert our records
        //Database.SetInitializer<DatabaseContext>(new DatabaseInitializer());
    }

    /// <summary>
    /// Default constructor
    /// </summary>
    public DatabaseContext()
        : base("DefaultConnection")
    {

        // Disable Lazy Loading
        base.Configuration.LazyLoadingEnabled = false;
    }

    /// <summary>
    /// Overrides the inherited OnModelCreated method.
    /// </summary>
    /// <param name="modelBuilder">The DbModelBuilder</param>
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        // Remove Cascading Delete
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

        // Map the TeamColours table
        modelBuilder.Entity<Team>()
            .HasMany(m => m.Colours)
            .WithMany()
            .Map(m =>
            {
                m.MapLeftKey("TeamId");
                m.MapRightKey("ColourId");
                m.ToTable("TeamColours");
            });
    }
}

nb:我已将其删除以便于阅读)

所以,我遇到的问题是当我尝试更新时,如果我尝试添加颜色,我会收到错误。 以下是我的基础知识库类:

public class Repository<T> : IDisposable, IRepository<T> where T : class
{
    private readonly DbContext context;
    private readonly DbSet<T> dbEntitySet;

    public Repository(DbContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        this.context = context;
        this.dbEntitySet = context.Set<T>();
    }

    public IQueryable<T> GetAll(params string[] includes)
    {
        IQueryable<T> query = this.dbEntitySet;
        foreach (var include in includes)
            query = query.Include(include);

        return query;
    }

    public void Create(T model)
    {
        this.dbEntitySet.Add(model);
    }

    public void Update(T model)
    {
        this.context.Entry<T>(model).State = EntityState.Modified;
    }

    public void Remove(T model)
    {
        this.context.Entry<T>(model).State = EntityState.Deleted;
    }

    public void Dispose()
    {
        this.context.Dispose();
    }
}

然后我有一个这样的基本服务类:

public class Service<T> where T : class
{
    private readonly IRepository<T> repository;

    protected IRepository<T> Repository
    {
        get { return this.repository; }
    }

    public Service(IUnitOfWork unitOfWork)
    {
        if (unitOfWork == null)
            throw new ArgumentNullException("unitOfWork");

        this.repository = unitOfWork.GetRepository<T>();
    }
}

最后这是我的 TeamService 类:

/// <summary>
/// Team service handles all team related functions
/// </summary>
public class TeamService : Service<Team>
{
    /// <summary>
    /// Default constructor
    /// </summary>
    /// <param name="unitOfWork"></param>
    public TeamService(IUnitOfWork unitOfWork) 
        : base(unitOfWork)
    {

    }

    /// <summary>
    /// Get all teams asynchronously
    /// </summary>
    /// <param name="includes">Eager loading includes</param>
    /// <returns>A list of colours</returns>
    public async Task<IList<Team>> GetAllAsync(params string[] includes)
    {
        return await this.Repository.GetAll(includes).ToListAsync();
    }

    /// <summary>
    /// Get a team by id
    /// </summary>
    /// <param name="id">The id of the colour</param>
    /// <param name="includes">Eager loading includes</param>
    /// <returns>A colour</returns>
    public async Task<Team> GetAsync(int id, params string[] includes)
    {
        var models = await this.GetAllAsync(includes);

        return models.Where(model => model.Id == id).SingleOrDefault();
    }

    /// <summary>
    /// Create a team
    /// </summary>
    /// <param name="model">The team model</param>
    public void Create(Team model)
    {

        // Create a team
        this.Repository.Create(model);
    }

    /// <summary>
    /// Update a team
    /// </summary>
    /// <param name="model">The team model</param>
    public void Update(Team model)
    {

        // Update a team
        this.Repository.Update(model);
    }

    /// <summary>
    /// Delete a team
    /// </summary>
    /// <param name="model">The team model</param>
    public void Remove(Team model)
    {

        // Remove a team
        this.Repository.Remove(model);
    }
}

我知道这里有很多代码,但如果有人可以帮助我,我需要给你我的整个过程:) 所以,如果我在我的控制器中创建一个更新方法,如下所示:

private async Task<IHttpActionResult> Save(TeamBindingViewModel model)
{

    // If our model is invalid, return the errors
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    // Create a list of colours
    var colours = new List<Colour>();

    // For each colour in our model, add to our list
    foreach (var colour in model.Colours)
        colours.Add(new Colour()
        {
            Id = colour.Id,
            Name = colour.Name,
            Hex = colour.Hex
        });

    // If there is an id
    if (model.Id > 0)
    {

        // Update our team
            await this.Update(model, colours);
    }
    else
    {

        // Create our team
        this.Create(model, colours);
    }

    // Save the database changes
    await this.unitOfWork.SaveChangesAsync();

    // Return Ok
    return Ok(model);
}

private void Create(TeamBindingViewModel model, IList<Colour> colours)
{

    // Create our new model
    var team = new Team()
    {
        Id = model.Id,
        Name = model.Name,
        Sport = model.Sport
    };

    // Assign our colours to our team
    team.Colours = colours;

    // Otherwise, create a new team
    this.service.Create(team);
}

private async Task Update(TeamBindingViewModel model, IList<Colour> colours)
{

    // Create our new model
    var team = new Team()
    {
        Id = model.Id,
        Name = model.Name,
        Sport = model.Sport
    };

    // Update the team
    this.service.Update(team);
}

private IList<Colour> GetDifference(IList<Colour> firstList, IList<Colour> secondList)
{

    // Create a new list
    var list = new List<Colour>();

    // Loop through the first list
    foreach (var first in firstList)
    {

        // Create a boolean and set to false
        var found = false;

        // Loop through the second list
        foreach (var second in secondList)
        {

            // If the first item id is the same as the second item id
            if (first.Id == second.Id)
            {

                // Mark it has being found
                found = true;
            }
        }

        // After we have looped through the second list, if we haven't found a match
        if (!found)
        {

            // Add the item to our list
            list.Add(first);
        }
    }

    // Return our differences
    return list;
}

更新将处理,一切正常。但是,如果我将更新方法更改为:

private async Task Update(TeamBindingViewModel model, IList<Colour> colours)
{

    // Create our new model
    var team = new Team()
    {
        Id = model.Id,
        Name = model.Name,
        Sport = model.Sport
    };

    // Get our current model
    var current = await this.service.GetAsync(model.Id, "Colours");
    var currentColours = current.Colours;

    // Assign our original colours to our team
    team.Colours = currentColours;

    // Get our colours to remove and add
    var coloursToRemove = GetDifference(currentColours, colours);
    var coloursToAdd = GetDifference(colours, currentColours);

    // Loop through our colours to remove and remove them
    if (coloursToRemove.Count > 0)
        foreach (var colour in coloursToRemove)
            team.Colours.Remove(colour);

    // Loop through the colours to add and add them
    if (coloursToAdd.Count > 0)
        foreach (var colour in coloursToAdd)
            team.Colours.Add(colour);

    // Update the team
    this.service.Update(team);
}

我收到此错误:

  
    

“exceptionMessage”:“附加'Models.Team'类型的实体失败,因为同一类型的另一个实体已经具有相同的主键值。当使用'Attach'方法或设置状态时,可能会发生这种情况。如果图中的任何实体具有冲突的键值,则实体为“未更改”或“已修改”。这可能是因为某些实体是新的且尚未接收到数据库生成的键值。在这种情况下,使用“添加”方法或“添加”实体状态以跟踪图表,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。“

  

我不确定为什么会出现此错误,但我认为它与尝试添加/删除查找表中的颜色有关。 任何人都可以为我提供这个问题的解决方案吗?

1 个答案:

答案 0 :(得分:1)

你的出现是因为你正试图更新&#34; team&#34;当你有&#34;当前&#34;变量holdes在同一范围内的实体试试这个:

private async Task Update(TeamBindingViewModel model, IList<Colour> colours)
{

    // Create our new model
    //var team = new Team()
    //{
    //    Id = model.Id,
    //    Name = model.Name,
    //    Sport = model.Sport
    //};

    // Get our current model
    var current = await this.service.GetAsync(model.Id, "Colours");

    current.Name = model.Name;
    current.Sport =  model.Sport;

    var currentColours = current.Colours;

    // Assign our original colours to our team
    //team.Colours = currentColours;

    // Get our colours to remove and add
    var coloursToRemove = GetDifference(currentColours, colours);
    var coloursToAdd = GetDifference(colours, currentColours);

    // Loop through our colours to remove and remove them
    if (coloursToRemove.Count > 0)
        foreach (var colour in coloursToRemove)
            current.Colours.Remove(colour);

    // Loop through the colours to add and add them
    if (coloursToAdd.Count > 0)
        foreach (var colour in coloursToAdd)
            current.Colours.Add(colour);

    // Update the team
    this.service.Update(current);
}