WPF/MVVM 应用程序中的数据访问使用啥模式

Posted

技术标签:

【中文标题】WPF/MVVM 应用程序中的数据访问使用啥模式【英文标题】:What pattern to use for Data Access in WPF/MVVM AppWPF/MVVM 应用程序中的数据访问使用什么模式 【发布时间】:2011-06-22 23:32:39 【问题描述】:

我有一个任务管理应用程序,它当前使用一个类来使用 Linq-to-SQL 访问数据;我想将数据访问移至项目中的单独解决方案。我想这样做的原因是为两件事做准备。首先是创建一个将在数据库“服务器”(它只是一台 win 7 PC)上运行的服务,该服务将定期查询任务并为到期的任务发送电子邮件提醒。其次是更改对 WCF 的数据访问,以便我可以从 WP7 访问任务(一旦它们在 Verizon 上)

返回的任务由绑定到视图模型的许多用户控件定义。目前,iQueryable 是在一系列语句中构建的,这些语句根据数据绑定成员缩小选择范围。然后查询由其他成员排序。一旦我将数据访问移出解决方案,使其无法访问 viewmodels 成员,我将需要传递相对大量的参数,并且我不确定执行此操作的正确方法是什么。我能想到的方法是:

    只需创建一个包含十几个或更多参数的方法(有人告诉我这是不好的做法) 创建一个包含所有参数的对象并传递它(与我的第一个选项似乎没有太大不同) 在数据访问解决方案中创建一个类,然后实例化它并设置它的每个属性,然后调用将返回 iQueryable(或 ObservableCollection)的方法,但我读到这种做法“味道不好”

我对 OOP 和 WPF 非常熟悉,这个简单的应用程序是我构建的最复杂的应用程序。我觉得我缺少一个模式或实践,建议?

如何构建查询的示例:

IQueryable<Issue> issuesQuery;

// Will select all items
issuesQuery = from i in db.Issues
      select i;

// Filters out pending issues
issuesQuery = issuesQuery.Where(i => i.IssIsPending == showPendingTasks);

// Filters out closed issues if they are not to be shown
if (includeClosedIssues == false) 
    issuesQuery = issuesQuery.Where(i => i.IssIsClosed == false);


// Filters out Regular Tasks if they are not to be shown
if (showTasks == false) 
    issuesQuery = from i in issuesQuery
             where i.IssIsOnStatusBoard == true
             select i;


// More filters are here

// Order the results      
issuesQuery = issuesQuery.OrderByDescending(
    i => i.IssIsSticky).ThenBy(
    i=>!i.IssDueDate.HasValue).ThenBy(
    i => i.IssDueDate).ThenBy(
    i => i.IssUrgency);

// an iQueryable is returned but is then converted to an ObservableCollection
return issuesQuery;

【问题讨论】:

其实第二点(带参数的对象)比较好,因为: 1)你可以添加或删除参数,方法仍然与其他客户端兼容; 2) 可以只设置必要的参数并使用默认值传递对象。但是我还没有理解第 3 点,如果对您来说没有太大的麻烦,您能否提供代码或文章的链接?您还可以查看 WCF 数据服务,但它们并不总是比常见的 WCF 服务更好。 在第三种方法中,我将创建一个公共类,其中包含所有参数的成员和一个返回集合的方法。要使用它,您将实例化它,设置所有成员然后调用方法(这将使用成员的值来确定要返回的项目) 我几周前刚购买了 John Sharps “Windows Communication Foundation 4”,但由于生日 Kindle 的原因延迟了启动它:) 我目前对此知之甚少 【参考方案1】:

我将向您解释如何使用服务,因为它们在 3-tired 架构中是强制性的,并且无法将模型与视图分开。

您可以使用两种不同的解决方案。

1. WCF 数据服务。

添加 -> 新项目 -> Wcf 数据服务。

然后指定DataContext的名称并设置访问权限。

public class WcfDataService1 : DataService<TestEntities>

    public static void InitializeService(DataServiceConfiguration config)
    
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        config.SetEntitySetAccessRule("*", EntitySetRights.All);
        config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
    

    /// <summary>
    /// Example of custom operations
    /// </summary>
    [WebGet]
    public IQueryable<Item> ItemsById(int id)
    
        return this.CurrentDataSource.Items.Where(i => i.Id == id);
    

在客户端应用程序中添加一个新的服务引用,然后您可以像使用本地数据库一样使用该服务:

var proxy = new TestEntities(new Uri("http://localhost:8513/WcfDataService1.svc/"));
var items = proxy.Items.Where(i => i.Id > 2 && i.Title.Contains("x1"));
var item2 = proxy.Execute<Item>(new Uri("ItemsById?Id=1", UriKind.Relative)).FirstOrDefault();

优点:无需编写GetItemsById、GetItemsByYear、GetTenItems等众多方法;您可以在客户端创建过滤查询。

缺点:服务操作不是静态类型的;调用自定义操作很困难,尤其是在有很多参数的情况下;如果使用自定义对象而不是实体,会有很多问题;

2。 WCF 服务

添加 -> 新项目 -> Wcf 服务

存储库类:

public class IssuesRepository

    public static List<Issue> GetIssues()
    
        //creating a new connection will not cause overhead because there is a pool of connections
        using (var db = new TestEntities()) 
        
            List<Expression<Func<Issue, bool>>> filters = new List<Expression<Func<Issue, bool>>>();

            filers.Add(i => i.IssIsPending == showPendingTasks);

            if (includeClosedIssues == false)
                filers.Add(i => i.IssIsClosed == false);

            if (showTasks == false)
                filers.Add(i => i.IssIsOnStatusBoard == true);


            IQueryable<Issue> issuesQuery = db.Items.AsQueryable();

            foreach (var filter in filters)
                issuesQuery = issuesQuery.Where(filter);

            issuesQuery = from i in issuesQuery
                          orderby i.IssIsSticky descending, !i.IssDueDate.HasValue ascending, i.IssDueDate, i.IssUrgency
                          select i;

            return issuesQuery.ToList(); //it will be serialized in any case
        
    

服务:

public class Service1 : IService1

    public List<Issue> GetIssues()
    
        return IssuesRepository.GetIssues();
    

优点:独立于协议;提供会话、安全性、事务。

因此,作为一个结论,如果您只需要一个 CRUD 功能,我建议使用 DataServices,如果您使用一组具有复杂逻辑的操作,我建议使用通用 WCF 服务。

【讨论】:

哇,感谢您的回复。看来我有一些功课要做。 @Mike B 只需阅读本书并编写一些测试应用程序即可更熟悉 WCF。之后很多事情都会变得简单。

以上是关于WPF/MVVM 应用程序中的数据访问使用啥模式的主要内容,如果未能解决你的问题,请参考以下文章

WPF MVVM更新列表框

WPF MVVM

WPF MVVM从入门到精通1:MVVM模式简介

WPF自学入门WPF MVVM模式Command命令

WPF MVVM实例三

WPF MVVM模式下动画的实现