Entity Framework 6 用被更新者的数据更新所有记录

Entity Framework 6 updates all records with data of the one getting updated

我正在尝试在我的应用程序中实施 entity framework 6,但我在对记录执行更新时遇到问题。

如果我在数据库中有 2 条记录,假设:

Id Name Lastname
1 Jason Momoa
2 Aqua Man

然后我将 ID 为 1 的对象从“Jason”更改为“Water”,并使用具有相同主键的新 Person 对象调用 UpdatePerson 函数。

结果将是:

Id Name Lastname
1 Water Momoa
2 Water Momoa

为什么会是这样的结果??我已经在四处寻找解决方案,但找不到任何线索。有人知道我做错了什么吗?

据我了解我使用的断开连接的数据上下文,可以简单地用主键知识更新记录。

参考 EF6

的页面

我的代码如下所示:

public class Person
{
    private int _id = -1;
    private string _name;
    private string _lastname;

    public int PersonId { get => _id; set => _id = value; }
    [Required]
    [MaxLength(255)]
    public string Name { get => _name; set => _name = value; }
    [Required]
    public string Lastname { get => _lastname; set => _lastname = value; }
}

DbContext:

public partial class Model1 : DbContext
{
    public Model1() : base("name=entity_test") { }

    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Person>().MapToStoredProcedures();
    }     
}

public class PersonModel
{
    public ObservableCollection<Person> GetPeople()
    {
        using (Model1 context = new Model1())
        {
            var list = context.People.AsNoTracking().ToList();
            if (list == null)
                return null;
            return new ObservableCollection<Person>(list);
        }
    }

    public void AddPerson(Person person)
    {
        using (Model1 context = new Model1())
        {
            context.People.Add(person);
            context.SaveChanges();
        }
    }

    public void UpdatePerson(Person person)
    {
        using (Model1 context = new Model1())
        {
            context.Entry(person).State = EntityState.Modified;
            context.SaveChanges();
        }
    }
}

编辑

表格显示效果不佳。

编辑 2

这是剩余的代码和 context.Database.Log = s => Console.WriteLine(s);

的输出

输出:

`Person_Update`


-- PersonId: '1' (Type = Int32, IsNullable = false)

-- Name: 'Water' (Type = String, IsNullable = false, Size = 5)

-- Lastname: 'Momoa' (Type = String, IsNullable = false, Size = 5)

-- Executing at 29.10.2021 16:46:05 +02:00

-- Completed in 198 ms with result: 2

代码:

public class NotifyBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            return true;
        }
        return false;
    }
}
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();

    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        PersonModel model = new PersonModel();

        if (DataContext is ViewModel vm)
        {
            vm.AddModifyPerson();
        }
    }
}

public class ViewModel : NotifyBase
{
    public ViewModel()
    {
        MiniProfilerEF6.Initialize();
        model = new PersonModel();

        using (var db = new Model1())
        {
            // create if not exists
            if (db.Database.CreateIfNotExists())
            {
                Console.WriteLine();
            }
            People = model.GetPeople();
        }
    }

    private PersonModel model;

    private ObservableCollection<Person> people = new ObservableCollection<Person>();
    private Person currentPerson = new Person();

    public ObservableCollection<Person> People { get => people; set => SetProperty(ref people, value); }
    public Person CurrentPerson { get => currentPerson; set => SetProperty(ref currentPerson, value); }

    public void AddModifyPerson()
    {
        if (CurrentPerson.PersonId == -1)
        {
            model.AddPerson(CurrentPerson);
        }
        else
        {
            model.UpdatePerson(
                new Person()
                {
                    PersonId = CurrentPerson.PersonId,
                    Lastname = CurrentPerson.Lastname,
                    Name = CurrentPerson.Name,
                });
        }
        People = model.GetPeople();
    }
}

编辑 3

来自 miniprofiler 的代码

    public void UpdatePerson(Person person)
    {
        var profiler = MiniProfiler.StartNew("My Profiler");
        using (MiniProfiler.Current.Step("Update_Sql"))
        {
            using (Model1 context = new Model1())
            {
                context.Entry(person).State = EntityState.Modified;
                context.SaveChanges();
            }
        }

        Console.WriteLine(MiniProfiler.Current.RenderPlainText());
    }

编辑 4

来自 mysql.general_log

的更新调用的输出
command_type argument
Init DB entity_test
Query SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
Query BEGIN
Query CALL Person_Update(1, 'Jason1', 'Momoa')
Query COMMIT

看起来更新过程确实没有执行 where 子句。如果我在运行call Person_Update_Custom(1, 'test','tes')中workbench所有行都更新了。这是存储过程:

    CREATE DEFINER=`root`@`localhost` PROCEDURE `Person_Update`(IN PersonId int,IN Name varchar(255) ,IN Lastname longtext)
    BEGIN 
    UPDATE `People` SET `Name`=Name, `Lastname`=Lastname WHERE `PersonId` = PersonId;
     END

所以在 miniprofiler(感谢 Armando Bracho)和 mysql 日志(感谢 Steve Py)中看到总是有一个 sql 查询和 Gert Arnold 指出程序可能是失败了,我专注于程序。

看起来,该过程将 PersonId 列名称与 CREATE PROCEDURE-header 中定义的 PersonId 变量混合在一起。

所以我添加了一些代码来手动定义更新过程参数。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<Person>().MapToStoredProcedures(p => p.Update(pp => pp.HasName("Person_Update").Parameter(pm => pm.Name, "db_Name").Parameter(pm => pm.Lastname, "db_Lastname").Parameter(pm => pm.PersonId, "db_PersonId")));
}      

将存储过程更改为:

CREATE DEFINER=`root`@`localhost` PROCEDURE `Person_Update`(IN db_PersonId int,IN db_Name varchar(255) ,IN db_Lastname longtext)
BEGIN 
UPDATE `People` SET `Name`=db_Name, `Lastname`=db_Lastname WHERE `PersonId` = db_PersonId;
 END

终于成功了!一排受影响。

编辑

MapToStoredProcedures改成

就够了
modelBuilder.Entity<Person>().MapToStoredProcedures(p => p.Update(pp => pp.HasName("Person_Update").Parameter(pm => pm.PersonId, "db_PersonId")));

这种方式不需要为所有属性定义它。