.NET WPF + Entity Framework 下简化多表CRUD实现的方案咨询
.NET WPF + Entity Framework 下简化多表CRUD实现的方案咨询
我完全懂你现在的感受——为每个表手写一套自定义集合类和带编辑功能的实体类,多表场景下重复工作简直是噩梦!下面给你几个实用的简化思路,能帮你少写很多重复代码:
1. 泛化ObservableCollection集合类
把你写的ArtistCollection改成泛型基类,让所有实体都能复用这套CRUD逻辑,不用每个表都单独写一个集合类:
public class GenericEntityCollection<T> : ObservableCollection<T> where T : class { private readonly DbContext _context; public GenericEntityCollection(IEnumerable<T> items, DbContext context) : base(items) { _context = context; } protected override void InsertItem(int index, T item) { _context.Set<T>().Add(item); base.InsertItem(index, item); Console.WriteLine($"InsertItem for {typeof(T).Name}"); } protected override void RemoveItem(int index) { var item = this[index]; _context.Set<T>().Remove(item); base.RemoveItem(index); } public int Save() { try { var savedCount = _context.SaveChanges(); Console.WriteLine($"Saved N° {savedCount} for {typeof(T).Name}"); return savedCount; } catch (Exception ex) { System.Windows.MessageBox.Show(ex.ToString()); return 0; } } public DbContext Context => _context; }
用法示例
后续任何表的集合都可以直接用这个泛型类,比如:
// Artist表集合 var artistCollection = new GenericEntityCollection<Artist>(context.Artists, context); // Album表集合 var albumCollection = new GenericEntityCollection<Album>(context.Albums, context);
2. 抽离通用编辑逻辑到实体基类
把Artist里的INotifyPropertyChanged和IEditableObject逻辑抽成一个通用基类,让所有EF实体继承它,避免每个实体重复写编辑代码:
public abstract class EntityBase : INotifyPropertyChanged, IEditableObject { private object _backup; private bool _inTransaction; public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public void BeginEdit() { // 用反射自动复制属性,避免手动写每个属性的备份逻辑 _backup = Activator.CreateInstance(GetType()); var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { if (prop.CanRead && prop.CanWrite) { prop.SetValue(_backup, prop.GetValue(this)); } } _inTransaction = true; Console.WriteLine($"- BeginEdit for {GetType().Name}"); } public void CancelEdit() { if (!_inTransaction) return; var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { if (prop.CanRead && prop.CanWrite) { prop.SetValue(this, prop.GetValue(_backup)); OnPropertyChanged(prop.Name); } } _backup = null; _inTransaction = false; Console.WriteLine($"- CancelEdit for {GetType().Name}"); } public void EndEdit() { if (!_inTransaction) return; var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { OnPropertyChanged(prop.Name); } _backup = null; _inTransaction = false; Console.WriteLine($"- EndEdit for {GetType().Name}"); } }
改造你的Artist实体
EF生成的部分类可以直接继承这个基类,不用修改自动生成的代码:
public partial class Artist : EntityBase { // 只保留EF生成的属性即可,编辑逻辑全部继承自基类 public int ArtistId { get; set; } public string Name { get; set; } }
注:如果担心反射性能,也可以用AutoMapper做对象复制,或者用T4模板自动生成属性备份代码,一般业务场景下反射足够用了。
3. 借助MVVM框架简化开发
如果项目允许引入第三方库,像Prism、MVVM Light或者Caliburn.Micro这类成熟的MVVM框架,都自带了封装好的可绑定集合(比如Prism的BindableCollection),有的还集成了EF的CRUD、编辑状态管理逻辑,能省掉大量自己造轮子的工作。
4. 代码生成工具自动化
如果需要高度定制化的代码,可以用T4模板或者Roslyn代码生成,自动为每个EF实体生成对应的集合类和继承自EntityBase的实体扩展类,完全不用手动编写重复代码。
这些方案都能帮你把重复代码降到最低:泛型基类是最直接的无依赖方案;MVVM框架能进一步提升开发效率;代码生成则适合需要定制化的复杂场景,你可以根据项目实际情况选择。
备注:内容来源于stack exchange,提问作者Brummell
相关产品推荐
相关产品推荐

