繁体   English   中英

实体框架使用查找表更新实体

[英]Entity Framework updating entity with lookup table

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

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'方法或将实体的状态设置为'如果图中的任何实体的键值有冲突,则为“不变”或“已修改”。这可能是因为某些实体是新的,尚未收到数据库生成的键值。在这种情况下,请使用“添加”方法或“已添加”实体状态以跟踪图表,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

我不确定为什么会收到此错误,但我认为这与尝试从查找表中添加/删除颜色有关。 谁能为我提供解决此问题的方法?

之所以会出现问题,是因为您在试图使“当前”变量将实体保留在同一范围内时尝试更新“团队”,请尝试以下操作:

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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM