wpf - Entity Framework 和 WPF 最佳实践

标签 wpf entity-framework

直接使用上下文是一个好主意吗?例如,假设我有一个客户数据库,用户可以按名称搜索他们,显示一个列表,选择一个,然后编辑该客户的属性。

看来我应该使用上下文来获取客户列表(映射到 POCO 或 CustomerViewModels),然后立即关闭上下文。然后,当用户选择 CustomerViewModels 之一时在列表中填充了 UI 的客户属性部分。

接下来他们可以更改名称、类型、网站地址、公司规模等。点击保存按钮后,我打开一个新上下文,使用 CustomerViewModel 中的 ID检索该客户记录,并更新其每个属性。最后,我调用SaveChanges()并关闭上下文。这是很多工作。

我的问题是为什么不直接使用上下文使其始终保持打开状态?我读过使用具有长生命周期范围的相同上下文非常糟糕,并且不可避免地会导致问题。我的假设是,如果该应用程序只能由一个人使用,我可以让上下文保持打开状态并做所有事情。但是,如果有很多用户,我想维护一个简洁的工作单元,从而根据每个请求打开和关闭上下文。

有什么建议么?谢谢。

@PGallagher - 感谢您的彻底回答。
@Brice - 您的意见也很有帮助

但是,@Manos D.“冗余代码的缩影”评论让我有点担心。让我通过一个例子。假设我将客户存储在数据库中,而我的客户属性之一是 CommunicationMethod。

[Flags]
public enum CommunicationMethod
{
    None = 0,
    Print = 1,
    Email = 2,
    Fax = 4
}

WPF 中我的管理客户页面的 UI 将在客户通信方式(打印、电子邮件、传真)下包含三个复选框。我无法将每个复选框绑定(bind)到该枚举,这没有意义。另外,如果用户点击了那个客户,起床去吃午饭怎么办……上下文在那里呆了几个小时,这很糟糕。相反,这是我的思考过程。

最终用户从列表中选择一个客户。我新建了一个上下文,找到该客户并返回一个 CustomerViewModel,然后关闭该上下文(为简单起见,我在这里留下了存储库)。
using(MyContext ctx = new MyContext())
{
    CurrentCustomerVM = new CustomerViewModel(ctx.Customers.Find(customerId));
}

现在用户可以选中/取消选中 Print、Email、Fax 按钮,因为它们绑定(bind)到 CustomerViewModel 中的三个 bool 属性,它也有一个 Save() 方法。开始。
public class CustomerViewModel : ViewModelBase
{
    Customer _customer;

    public CustomerViewModel(Customer customer)
    {
        _customer = customer;
    }


    public bool CommunicateViaEmail
    {
        get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email); }
        set
        {
            if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email)) return;

            if (value)
                _customer.CommunicationMethod |= CommunicationMethod.Email;
            else
                _customer.CommunicationMethod &= ~CommunicationMethod.Email;
        }
    }
    public bool CommunicateViaFax
    {
        get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax); }
        set
        {
            if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax)) return;

            if (value)
                _customer.CommunicationMethod |= CommunicationMethod.Fax;
            else
                _customer.CommunicationMethod &= ~CommunicationMethod.Fax;
        }
    }
    public bool CommunicateViaPrint
    {
        get { return _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print); }
        set
        {
            if (value == _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print)) return;

            if (value)
                _customer.CommunicateViaPrint |= CommunicationMethod.Print;
            else
                _customer.CommunicateViaPrint &= ~CommunicationMethod.Print;
        }
    }

    public void Save()
    {
        using (MyContext ctx = new MyContext())
        {
            var toUpdate = ctx.Customers.Find(_customer.Id);
            toUpdate.CommunicateViaEmail = _customer.CommunicateViaEmail;
            toUpdate.CommunicateViaFax = _customer.CommunicateViaFax;
            toUpdate.CommunicateViaPrint = _customer.CommunicateViaPrint;

            ctx.SaveChanges();
        }
    }
}

你觉得这有什么问题吗?

最佳答案

可以使用长时间运行的上下文;您只需要了解其中的含义。

上下文代表一个工作单元。每当您调用 SaveChanges 时,对正在跟踪的实体的所有未决更改都将保存到数据库中。因此,您需要将每个上下文的范围限定在有意义的范围内。例如,如果您有一个用于管理客户的选项卡和另一个用于管理产品的选项卡,您可以为每个选项卡使用一个上下文,这样当用户在客户选项卡上单击“保存”时,他们对产品所做的所有更改都不会被保存。

上下文跟踪大量实体也会减慢 DetectChanges。减轻这种情况的一种方法是使用更改跟踪代理。

由于加载实体和保存实体之间的时间可能很长,因此遇到乐观并发异常的机会比短期上下文大。当实体在加载和保存之间发生外部更改时,会发生这些异常。 Handling these exceptions非常简单,但仍然需要注意。

您可以在 WPF 中使用长生命周期上下文做的一件很酷的事情是绑定(bind)到 DbSet.Local 属性(例如 context.Customers.Local)。这是一个 ObservableCollection,其中包含所有未标记为删除的跟踪实体。

希望这可以为您提供更多信息,以帮助您决定使用哪种方法来提供帮助。

关于wpf - Entity Framework 和 WPF 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15012953/

相关文章:

WPF:自动完成文本框,...再次

c# - 如何在查询语法中编写 Take(1)

c# - RowEditEnding 事件获取空值

外部 dll 中的 c#/wpf OpenMP

c# - wpf:usercontrol 与 customcontrol 性能问题

c# - WPF 在 XAML 的继承类中使用重写属性

.net - 如何在多个 .NET 应用程序之间共享 DAL 和 BLL?

c# - 具有 asp 网络标识的自定义实体(一对多)

sql - 使用包含多个选项的 Entity Framework 查询

c# - 如何从两个窗口访问一个类(C# WPF)