简体   繁体   English

实体框架更新查找表正在将项目添加到另一个表

[英]Entity Framework update lookup table is adding items to another table

I have an issue with a lookup table. 查询表有问题。 I have a form that allows me to select colours from a list that will be part of a team. 我有一个表格,可以让我从团队的列表中选择颜色。 The update method looks like this: 更新方法如下所示:

[HttpPut]
[Route("")]
/// <summary>
/// Update a team
/// </summary>
/// <param name="model">The team model</param>
/// <returns>Nothing</returns>
public async Task<IHttpActionResult> Update(TeamBindingViewModel model)
{

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

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

    // Make changes to our team
    team.Name = model.Name;
    team.Sport = model.Sport;

    // Find out which colours need adding and removing
    var coloursToRemove = GetDifference(team.Colours, model.Colours);
    var coloursToAdd = GetDifference(model.Colours, team.Colours);

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

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

    // Return Ok
    return Ok(model);
}

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

If I put a breakpoint on the unitOfWork.SaveChangesAsync() then I can see that the team colours is using the existing colours already in my database (all the id's match up. But once that SaveChangesAsync executes, it creates a new row in the Colours table with a duplicate of the colour I just selected. I don't want it to create a new row, I want it to use the selected colour. 如果我在unitOfWork.SaveChangesAsync()上设置一个断点,那么我可以看到团队颜色正在使用数据库中已经存在的现有颜色(所有ID都匹配。但是一旦执行SaveChangesAsync ,它就会在Colors中创建一个新行与我刚刚选择的颜色重复的表格,我不希望它创建新的行,我希望它使用选择的颜色。

I am not sure how I can give more information; 我不确定如何提供更多信息; I hope this is enough of a description for someone to be able to help me! 我希望这足以为某人提供帮助的描述!

Update 更新

So I have decided to look at the SQL that is generated. 因此,我决定查看生成的SQL。 I have a colour in my Colours table that looks like this: 我的“ 颜色”表中有一个看起来像这样的颜色

10 Red (Pms200) ff0000 10红色(Pms200)ff0000

So the Id is 10 , the Name is Red (Pms200) and the Hex is ff0000 . 因此, Id10名称Red(Pms200)十六进制ff0000 If I select that colour when editing a team and press submit. 如果我在编辑团队时选择该颜色,然后按提交。 It runs the Update method shown above and I have changed my DbContext to log the sql by adding this line in the constructor: 它运行上面显示的Update方法,并且通过在构造函数中添加以下行,我更改了DbContext来记录sql:

this.Database.Log = s => Debug.WriteLine(s);

So, when the SaveChangesAsync code exectues, the following SQL is generated: 因此,当执行SaveChangesAsync代码时,将生成以下SQL:

Started transaction at 13/04/2015 12:25:03 +01:00

UPDATE [dbo].[Teams]
SET [Name] = @0, [Sport] = @1
WHERE ([Id] = @2)

-- @0: 'Testing' (Type = String, Size = -1)

-- @1: 'ultimate-frisbee' (Type = String, Size = -1)

-- @2: '1' (Type = Int32)

-- Executing asynchronously at 13/04/2015 12:25:03 +01:00

-- Completed in 5 ms with result: 1



INSERT [dbo].[Colours]([Name], [Hex])
VALUES (@0, @1)
SELECT [Id]
FROM [dbo].[Colours]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()


-- @0: 'Red (Pms200)' (Type = String, Size = -1)

-- @1: 'ff0000' (Type = String, Size = -1)

-- Executing asynchronously at 13/04/2015 12:25:03 +01:00

-- Completed in 1 ms with result: SqlDataReader



INSERT [dbo].[TeamColours]([TeamId], [ColourId])
VALUES (@0, @1)

-- @0: '1' (Type = Int32)

-- @1: '43' (Type = Int32)

-- Executing asynchronously at 13/04/2015 12:25:03 +01:00

-- Completed in 1 ms with result: 1



Committed transaction at 13/04/2015 12:25:03 +01:00

Closed connection at 13/04/2015 12:25:03 +01:00

Now the problem here is that it should be only inserting something into the TeamColours table and not the Colours table. 现在的问题是,它应该只在TeamColours表中插入内容,而不是在Colors表中插入内容。 I can't figure out why.... 我不知道为什么...

And because someone has asked to see my UnitOfWork class, here it is: 由于有人要求查看我的UnitOfWork类,因此它是:

public class UnitOfWork<TContext> : IUnitOfWork where TContext : DbContext, new()
{
    private readonly DbContext context;
    private Dictionary<Type, object> repositories;

    public DbContext Context { get { return this.context; } }

    public UnitOfWork()
    {
        this.context = new TContext();
        repositories = new Dictionary<Type, object>();
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        if (repositories.Keys.Contains(typeof(TEntity)))
            return repositories[typeof(TEntity)] as IRepository<TEntity>;

        var repository = new Repository<TEntity>(context);

        repositories.Add(typeof(TEntity), repository);

        return repository;
    }

    public async Task SaveChangesAsync()
    {
        try
        {
            await this.context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            ex.Entries.First().Reload();
        }
    }

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

Although I am certain that is not causing the issue. 尽管我确定这不是导致问题的原因。

try this 尝试这个

public async Task<IHttpActionResult> Update(TeamBindingViewModel model)
{
    // If our model is invalid, return the errors
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

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

    // Make changes to our team
    team.Name = model.Name;
    team.Sport = model.Sport;

    //remove
    foreach (var colour in team.Colours.ToList())
    {
        if (!model.Colours.Any(c => c.Id == colour.Id))
            team.Colours.Remove(colour);
    }

    //add
    foreach (var colour in model.Colours)
    {
        if (!team.Colours.Any(c => c.Id == colour.Id))
            team.Colours.Add(colour);
    }

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

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

    // Return Ok
    return Ok(model);
}

Model.Colors is not associated a context. Model.Colors没有关联上下文。 So your Db Context tries to add new one. 因此,您的Db上下文会尝试添加新的。

1 -Get colors from repository 1-从存储库获取颜色

var newColours = repository.ListColours(model.Colors.Select(m=>m.Id));  

2- Assign new colors to team 2-为团队分配新颜色

team.Colours = newColours;

this.service.Update(team);

await this.unitOfWork.SaveChangesAsync();

EF will automatically operate remove and add operations. EF将自动执行删除和添加操作。

I have not tested this code. 我尚未测试此代码。 But I hope EntityFramework smarter then I thought. 但是我希望EntityFramework可以比我想象的更聪明。

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

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