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")));
这种方式不需要为所有属性定义它。
我正在尝试在我的应用程序中实施 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")));
这种方式不需要为所有属性定义它。