将实体框架与WPF DataBinding一起使用的最佳实践

时间:2009-03-09 23:34:20

标签: wpf entity-framework

我正在构建我的第一个真正的WPF应用程序(即第一个打算供我以外的人使用),我仍然围绕着在WPF中做事的最佳方式。这是一个相当简单的数据访问应用程序,使用仍然相当新的实体框架,但我无法在线找到大量的指导,以便将这两种技术(WPF和EF)结合使用的最佳方式。所以我想我会抛弃我是如何接近它的,看看是否有人有更好的建议。

  • 我正在使用SQL Server 2008的实体框架.EF让我觉得它比它需要的要复杂得多,而且还不成熟,但是Linq-to-SQL显然已经死了,所以我不妨使用MS似乎关注的技术。

  • 这是一个简单的应用程序,所以我(还)认为不适合在它周围构建一个单独的数据层。当我想获取数据时,我使用相当简单的Linq-to-Entity查询,通常直接来自我的代码隐藏,例如:

    var families = from family in entities.Family.Include("Person")
               orderby family.PrimaryLastName, family.Tag
               select family;
    
  • Linq-to-Entity查询返回一个IOrderedQueryable结果,该结果不会自动反映基础数据的变化,例如,如果我通过代码向实体数据模型添加新记录,则存在这个新的记录不会自动反映在引用Linq查询的各种控件中。因此,我将这些查询的结果抛入ObservableCollection,以捕获基础数据更改:

    familyOC = new ObservableCollection<Family>(families.ToList());
    
  • 然后我将ObservableCollection映射到CollectionViewSource,这样我就可以进行过滤,排序等,而无需返回数据库。

    familyCVS.Source = familyOC;
    familyCVS.View.Filter = new Predicate<object>(ApplyFamilyFilter);
    familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("PrimaryLastName", System.ComponentModel.ListSortDirection.Ascending));
    familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("Tag", System.ComponentModel.ListSortDirection.Ascending));
    
  • 然后我将各种控件和what-not绑定到CollectionViewSource:

    <ListBox DockPanel.Dock="Bottom" Margin="5,5,5,5" 
        Name="familyList" 
        ItemsSource="{Binding Source={StaticResource familyCVS}, Path=., Mode=TwoWay}" 
        IsSynchronizedWithCurrentItem="True" 
        ItemTemplate="{StaticResource familyTemplate}" 
        SelectionChanged="familyList_SelectionChanged" />
    
  • 当我需要添加或删除记录/对象时,我从实体数据模型和ObservableCollection手动执行此操作:

    private void DeletePerson(Person person)
    {
        entities.DeleteObject(person);
        entities.SaveChanges();
        personOC.Remove(person);
    }
    
  • 我通常使用StackPanel和DockPanel控件来定位元素。有时我会使用Grid,但似乎很难维护:如果要在网格顶部添加新行,则必须触摸网格直接托管的每个控件,以告诉它使用新行。 Uggh。 (微软似乎从未真正获得DRY概念。)

  • 我几乎从不使用VS WPF设计器来添加,修改或定位控件。 VS附带的WPF设计器对于查看表单的外观有点模糊,但即使如此,也不是真的,特别是如果您使用的数据模板不能绑定到可用的数据模板设计时间。如果我需要编辑我的XAML,我会像男人一样手动操作。

  • 我的大部分真实代码都是使用C#而不是XAML。正如我之前提到的elsewhere,完全不同于我还不习惯“思考”它的事实,XAML让我觉得它是一种笨重,丑陋的语言,也恰好伴随着糟糕的设计师和智能感知支持,无法调试。 Uggh。因此,每当我能够清楚地看到如何在C#代码中执行某些操作时,我无法轻易地看到如何在XAML中执行操作,而是在C#中执行此操作,并且没有道歉。关于如何在WPF页面中使用代码隐藏(例如,用于事件处理)这是一个很好的做法,已经有很多文章,但至少到目前为止,这对我来说毫无意义。当我能使用像C#一样漂亮,干净的语言,拥有世界一流的编辑器,近乎完美的时候,我为什么要用一种丑陋,笨重的语言做一些语法,一个令人难以置信的语法,一个令人惊讶的糟糕的编辑器,几乎没有类型的安全性intellisense,无与伦比的安全性?

这就是我所在的地方。有什么建议?我错过了这方面的任何重要部分吗?我应该考虑采取哪些不同的做法?

6 个答案:

答案 0 :(得分:19)

您需要实现存储库模式以从EF

中分离WPF问题

然后,您可以使用泛型来降低EF到CollectionViewSource处理的复杂性

设计良好的存储库应该降低代码级别并允许替换任何ORM(适当的测试需要)

这方面的一些想法就在这里

http://blog.nicktown.info/2008/12/10/using-a-collectionviewsource-to-display-a-sorted-entitycollection.aspx

答案 1 :(得分:7)

另外,我认为你不需要在这里做一个ToList()。我相信ObservableCollection()接受一个家庭已经存在的IEnumerable。如果您执行ToList,然后将其传递给ObservableCollection,那么我认为您将遍历所有记录两次。

familyOC = new ObservableCollection<Family>(families.ToList());

相反,试试这个,这应该快一点:

familyOC = new ObservableCollection<Family>(families);

答案 2 :(得分:5)

我知道你来自哪里。这个article by Josh Smith帮助我改变(或开始改变)心态,这样你就可以从WPF中获益,而不是把它视为一个奇怪的,阻碍的,难以调试和不友好的框架!

答案 3 :(得分:4)

我的建议是,如果可能的话,使用Expression Blend来设计你的界面,而不是使用Visual Behind,而不是使用Visual Studio设计器,它将为你节省大量的时间。还尝试重新考虑使用C#而不是xaml。如果您使用“WPF Way”,Xaml就不那么难看了。很多时候,当我认为使用后面的代码而不是xaml更容易时,这是因为我做错了方法并且需要重新思考它应该如何最好地使用WPF / xaml。一旦你习惯了,Xaml就很棒了。我还使用了实体框架,但它还不是很好。我更喜欢NHibernate。

答案 4 :(得分:2)

我在我的博客中关注了此链接,并希望提及我在EF中找到的其他内容。有点偏离主题,但不完全。

我注意到在使用.Include时EF会出现一些疯狂的性能问题。 MS解释了为什么在他们网站上的一篇文章中,所以我实际上开始将我的大部分代码转移到使用.Load方法。

因为这是一项繁琐的工作,因为我无法找到另一种方法......我创建了自己的方法“IncludeByRoundTrip”。它的作用是获取一个对象路径并确保加载整个路径。最终结果与在幕后使用include时相同,我只是在对象图中的所有属性上调用Load。

如果存在这样的机制,它类似于执行order.Load(“Customer.Address”)之类的操作。无论哪种方式,请在我的博客上查看,并告诉我你的发现。我很想知道其他人是否注意到使用Include减速并且如果你有其他方法来攻击这种情况。

我的解决方案有更多信息,请访问: http://blog.nicktown.info/2009/07/27/method-to-load-an-entire-object-graph-using-adonet-entity-framework.aspx

再次,抱歉这有点偏离主题,但我期待你的回复。

答案 5 :(得分:1)

另一个工具可能是BindableLINQ

Bindable LINQ是LINQ的一组扩展,用于添加数据绑定并将传播功能更改为标准LINQ查询