Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# EF Core-一次性DbContext和Attach()-或-DbContext作为成员或断开连接的实体_C#_.net_Wpf_Datagrid_Entity Framework Core - Fatal编程技术网

C# EF Core-一次性DbContext和Attach()-或-DbContext作为成员或断开连接的实体

C# EF Core-一次性DbContext和Attach()-或-DbContext作为成员或断开连接的实体,c#,.net,wpf,datagrid,entity-framework-core,C#,.net,Wpf,Datagrid,Entity Framework Core,我不确定如何为绑定到WPF数据网格的实体正确使用DbContext 在用户控件加载期间,如何正确地“重新连接”并将对数据库的更改保存到加载到datagrid的所有实体 我使用DbContext作为成员变量,使用ObservableCollection作为Datagrids的数据源。所以到目前为止一切都很好,不需要在下面的代码中搜索错误。只是为了展示我到目前为止所做的一切 // Old code - working perfectly as desired private TestMenuData

我不确定如何为绑定到WPF数据网格的实体正确使用DbContext

在用户控件加载期间,如何正确地“重新连接”并将对数据库的更改保存到加载到datagrid的所有实体

我使用DbContext作为成员变量,使用ObservableCollection作为Datagrids的数据源。所以到目前为止一切都很好,不需要在下面的代码中搜索错误。只是为了展示我到目前为止所做的一切

// Old code - working perfectly as desired
private TestMenuDataContext _Db;
public ObservableCollection<Vendor> Vendors { get; set; }

private void ucGeneralSettings_Loaded(object sender, RoutedEventArgs e) {
    //Do not load your data at design time.
    if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) {
        _Db = new TestMenuDataContext();
        _Db.Database.EnsureCreated();
        Vendors = new ObservableCollection<Vendor>(_Db.Vendors);
        Vendors.CollectionChanged += Vendors_CollectionChanged;
        vendorDataGrid.ItemsSource = Vendors;

    }
}

private void Vendors_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
    switch (e.Action) {
        case NotifyCollectionChangedAction.Add:
            _Db.Vendors.AddRange(e.NewItems.Cast<Vendor>());
            foreach (var vendor in e.NewItems.Cast<Vendor>()) {
                vendor.TimeStamp = DateTime.Now;
                vendor.UserName = Environment.UserName;
            }
            break;
        case NotifyCollectionChangedAction.Remove:
            _Db.Vendors.RemoveRange(e.OldItems.Cast<Vendor>());
            break;
    }
}

private void SaveSettingsButton_Click(object sender, RoutedEventArgs e) {
    var queryDeletedUsedVendor = _Db.TestMenu.Where(t => !Vendors.Any(v => v.Name== t.Vendor));
    if (queryDeletedUsedVendor.Any())       {
        _AppManager.AddStatusMessage($"Saving settings not possible. Vendor {queryDeletedUsedVendor.FirstOrDefault().Vendor} deleted but it is in use in the Test Menu!", State.Error);
        return;
    }

    try {
        _Db.SaveChanges();
        _AppManager.AddStatusMessage("Settings saved", State.Ok);
    }
    catch (Exception ex) {
        _AppManager.AddStatusMessage($"Saving data failed {ex.Message}", State.Error);
    }

    // fire delegate event to inform MainWindow 
    onDatabaseUpdated?.Invoke(this);
}

private void ucGeneralSettings_Unloaded(object sender, RoutedEventArgs e) {
    if (_Db != null)
        _Db.Dispose();
}
我真的需要在所有实体上循环,附加每个实体并手动检查删除或添加的实体吗?我不希望每次出现CollectionChanged事件时都打开DbContext。我不敢相信会这么复杂。。。因此,目前我更倾向于使用DbContext作为以前使用的成员变量…


如果我在谷歌上搜索更正,则未实现的断开连接的实体不打算在具有DB Server连接的WPF应用程序中使用,它们将用于n层环境。所以这不是要搜索的主题,对吗?

我不希望每次出现
CollectionChanged
事件时都打开
DbContext

那就不要。在视图模型中创建一个
TestMenuDataContext
,并像以前一样使用这个

所以现在我更喜欢使用
DbContext
作为成员变量,就像以前一样

没有什么能阻止你这么做,是吗?显然,在本例中,您确实希望视图模型的每个实例都有一个
TestMenuDataContext
。只需在视图模型中(例如在其构造函数中)创建一次
TestMenuDataContext
,然后在
CollectionChanged
事件处理程序中使用此函数。或者在save方法中创建上下文

DbContext
的最佳生存期当然会因您的需求而有所不同。一般来说,您应该使用短期上下文,但在这种情况下,您似乎确实希望(并且应该使用)对
数据网格中的实体对象所做的所有更改都使用相同的上下文

当然,另一个选项是在按下“保存”按钮时(并非每次修改内存中的集合时)创建上下文并附加实体。

侧注:

在MVVM
ObservableCollection.CollectionChanged
中,应该通知视图模型中的更改,以及相应的ViewModel。我不建议让视图修改
ObservableCollection
,然后使用
CollectionChanged
来反映ViewModel中的更改。尝试保持视图模型->视图通知流,而不是相反方向。*每个更改都在视图模型中完成,并反映在视图中

第一种方法: 基本上分离应用程序逻辑和数据访问,这正是viewmodel的用途

public class YourPageViewModel
{
    private readonly ObservableCollection<VendorItemVm> _deletedVendors = new ObservableCollection<VendorItemVm>();
    public List<VendorItemVm> Vendors { get; } = new List<VendorItemVm>();

    void Add()
    {
        Vendors.Add(new VendorItemVm
        {
            IsNew = true,
            Id = new Guid(),
            UserName = "New Vendor",
        });
    }

    void Remove(VendorItemVm vendor)
    {
        Vendors.Remove(vendor);
        _deletedVendors.Add(vendor); 
    }

    async Task Load()
    {
        using(var db = new DbContext())
        {
            var vendors = db.Vendors.AsNoTracking().ToList();
            foreach(var entity in vendors)
            {
                Vendors.Add(new VendorItemVm
                {
                    Id = entity.Id,
                    Name = entity.Name,
                });
            }
        }
    }

    async Task Save()
    {
        using (var db = new DbContext())
        {
            //convert viewmodels to entities
            var newVendorsEntities = Vendors
                .Where(v => v.IsNew)
                .Select(v => new Vendor
                {
                    Id = v.Id,
                    UserName = v.UserName,
                    TimeSpan = DateTime.Now,
                })
                .ToArray();

            //add new entities
            foreach (var vm in Vendors.Where(v => v.IsNew))
            {
                var entity = new Vendor
                {
                    Id = vm.Id,
                    UserName = vm.UserName,
                    TimeSpan = DateTime.Now,
                };
                db.Vendors.Add(vendor);
            }

            //delete removed entities:
            foreach(var vm in _deletedVendors)
            {
                var entity = new Vendor { Id = vm.Id };
                db.Vendors.Attach(entity);
                db.Ventors.Remove(entity);
                db.Vendors.Add(vendor);
            }

            await db.SaveChangesAsync();

            //reset change tracking
            foreach (var vm in Vendors) vm.IsNew = false;
            _deletedVendors.Clear();
        }
    }
}
公共类YourPageViewModel
{
私有只读ObservableCollection _deletedVendors=新ObservableCollection();
公共列表供应商{get;}=new List();
void Add()
{
添加(新的VendorItemVm)
{
IsNew=true,
Id=新Guid(),
UserName=“新供应商”,
});
}
作废删除(VendorItemVm供应商)
{
供应商。删除(供应商);
_deletedVendors.Add(供应商);
}
异步任务加载()
{
使用(var db=new DbContext())
{
var vendors=db.vendors.AsNoTracking().ToList();
foreach(供应商中的var实体)
{
添加(新的VendorItemVm)
{
Id=entity.Id,
Name=entity.Name,
});
}
}
}
异步任务保存()
{
使用(var db=new DbContext())
{
//将视图模型转换为实体
var newVendorsEntities=供应商
.其中(v=>v.IsNew)
.选择(v=>新供应商
{
Id=v.Id,
UserName=v.UserName,
TimeSpan=日期时间。现在,
})
.ToArray();
//添加新实体
foreach(Vendors.Where中的var vm(v=>v.IsNew))
{
var实体=新供应商
{
Id=vm.Id,
UserName=vm.UserName,
TimeSpan=日期时间。现在,
};
db.Vendors.Add(供应商);
}
//删除删除的实体:
foreach(在_deletedVendors中的var vm)
{
var entity=newvendor{Id=vm.Id};
db.供应商.附件(实体);
db.Ventors.Remove(实体);
db.Vendors.Add(供应商);
}
等待db.saveChangesSync();
//重置更改跟踪
foreach(供应商中的var vm)vm.IsNew=false;
_deletedVendors.Clear();
}
}
}
第二种方法: 在前面的示例中,我们基本上实现了自己的基本工作单元模式。然而,DbContext已经实现了UoW和变更跟踪模式

我们将创建DBContext的实例,但我们将仅将其用于跟踪添加/删除的实体:

public class YourPageViewModel
{
    MyDbContext _myUoW;
    public ObservableCollection<Vendor> Vendors { get; } = new ObservableCollection<Vendor>();

    void Add()
    {
        var entity = new Vendor
        {
            Id = new Guid(),
            UserName = "New Vendor",
        };
        Vendors.Add(entity)
        _myUoW.Vendors.Add(entity);
    }

    void Remove(VendorItemVm vendor)
    {
        Vendors.Remove(vendor);
        _myUoW.Vendors.Attach(entity);
        _myUoW.Vendors.Add(entity);
    }

    async Task Load()
    {
        using(var db = new MyDbContext())
        {
            Vendors = db.Vendors.AsNoTracking.ToList();
            foreach(var entity in vendors) Vendors.Add(entity);
        }
        _myUoW = new MyDbContext();
        //if you want to track also changes to each vendor entity, use _myUoW to select the entities, so they will be tracked. 
        //In that case you don't need to attach it to remove
    }

    async Task Save()
    {
        //add new entities and delete removed entities
        _myUoW.SaveChanges();

        //reset change tracking
        _myUoW.Dispose();
        _myUoW = new MyDbContext();
    }
}
公共类YourPageViewModel
{
MyDbContext_myUoW;
公共ObservableCollection供应商{get;}=new ObservableCollection();
void Add()
{
var实体=新供应商
{
Id=新Guid(),
UserName=“新供应商”,
};
供应商。添加(实体)
_myUoW.Vendors.Add(实体);
}
作废删除(VendorItemVm供应商)
{
供应商。删除(供应商);
_myUoW.Vendors.Attach(实体);
_myUoW.Vendors.Add(实体);
}
异步任务加载()
{
我们
public class YourPageViewModel
{
    MyDbContext _myUoW;
    public ObservableCollection<Vendor> Vendors { get; } = new ObservableCollection<Vendor>();

    void Add()
    {
        var entity = new Vendor
        {
            Id = new Guid(),
            UserName = "New Vendor",
        };
        Vendors.Add(entity)
        _myUoW.Vendors.Add(entity);
    }

    void Remove(VendorItemVm vendor)
    {
        Vendors.Remove(vendor);
        _myUoW.Vendors.Attach(entity);
        _myUoW.Vendors.Add(entity);
    }

    async Task Load()
    {
        using(var db = new MyDbContext())
        {
            Vendors = db.Vendors.AsNoTracking.ToList();
            foreach(var entity in vendors) Vendors.Add(entity);
        }
        _myUoW = new MyDbContext();
        //if you want to track also changes to each vendor entity, use _myUoW to select the entities, so they will be tracked. 
        //In that case you don't need to attach it to remove
    }

    async Task Save()
    {
        //add new entities and delete removed entities
        _myUoW.SaveChanges();

        //reset change tracking
        _myUoW.Dispose();
        _myUoW = new MyDbContext();
    }
}