MVVM轻量级数据网格从两个关系数据库表加载

时间:2010-07-19 12:55:48

标签: silverlight mvvm datagrid light

如何使用MVVM灯加载带有两个相关表的DataGrid,我使用的是.NET RIA和Silverlight 4.

例如,如果我的数据表是:

userInfo- userID,Name,AddressID
地址 - 地址ID,街道名称,邮编

如何创建显示[Name,StreetName,ZIp]

的数据网格

2 个答案:

答案 0 :(得分:1)

首先,您必须在DomainService类的GetInfo中包含Address表,如下所示......

  [Query]
  public IQueryable<UserInfo> GetUserInfos()
    {
        return this.ObjectContext.UserInfos.Include("Address");
    }

然后在元数据文件中,您必须在

上方添加[Include]
  [Include]
        public Addresses Address{ get; set; }
        public int AddressID { get; set; }

现在构建解决方案。 现在在Xaml中你可以像这样使用

  <sdk:DataGrid ItemsSource="{Binding UserList, Mode=TwoWay}" SelectedItem="{Binding CurrentUser, Mode=TwoWay}" Margin="0,0,0,2" AutoGenerateColumns="False">
        <sdk:DataGrid.Columns>
            <sdk:DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
            <sdk:DataGridTextColumn Header="Street Name" Binding="{Binding Path=Address.StreetName}"/>
            <sdk:DataGridTextColumn Header="Zip" Binding="{Binding Path=Address.Zip}"/>
        </sdk:DataGrid.Columns>

    </sdk:DataGrid>

答案 1 :(得分:0)

这里有几种可行的方法。我会解释两个想到的。首先,使用已在数据库中定义的关系。第二是通过自定义模型类返回。

选项1: 我假设您已经在Web项目上的数据库中创建了一个实体框架模型(带有关系),并创建了DomainService来托管模型。 !!!创建模型时要做的一件事就是为模型创建元数据类! (我在前几次错过了这一点,修改模型的行为至关重要,例如你在这里需要的)

在元数据模型中,您将找到关联属性,并使用[Include]属性对其进行修饰。这是我在另一个带有WorklanDetail的项目中的示例,我想返回相关的作业:

[MetadataTypeAttribute(typeof(WorkplanDetailMetadata))]
public partial class WorkplanDetail
{
    internal sealed class WorkplanDetailMetadata
    {
        [Include]
        public EntityCollection<Assignment> Assignments { get; set; }
    }
}

然后,您可以在Silverlight应用程序中引用该属性,并且可以提供您的地址数据。

要绑定单个实体(EntityReference,而不是集合),您只需使用属性访问数据网格绑定上的子实体...例如:

Text="{Binding Path=Address.StreetName}"

这是我所知道的最简单的方法。

选项2需要创建自己的自定义类(您必须至少具有使用[Key]属性修饰的属性,以便于传输到客户端/从客户端传输)。这是一个例子,我已经习惯了获取foldersearch结果信息:

public class FolderSearchResult
{
    [Key]
    public string EFOLDERID { get; set; }
    public string Subject { get; set; }
    public string FolderName { get; set; }
}

关键是EFOLDERID属性具有[Key]属性,该属性唯一地标识每个项目,就像数据库中的PK一样。

然后在你的服务类中你可以这样返回:

public IEnumerable<FolderSearchResult> GetFolderResults(string search)
    {
        var query = from ge in this.ObjectContext.Generic_Engagement
                    from f in this.ObjectContext.eFolders
                    where ge.EFOLDERID == f.eFolderID &
                    f.eArchived == 0 &
                    f.eSubject.Contains(search) &

                    (from wp in this.ObjectContext.Workplans
                     where wp.EFOLDERID == f.eFolderID
                     select wp).Count() == 0 &

                     (from r in this.ObjectContext.Resources
                      where r.EFOLDERID == f.eFolderID
                      select r).Count() == 0

                    select new FolderSearchResult()
                      {
                        EFOLDERID = f.eFolderID,
                        FolderName = f.eFolderName,
                        Subject = f.eSubject
                      };
        return query.AsEnumerable<FolderSearchResult>();
    }

关于这种方法的几点说明:

  1. 当您不需要只读访问权限时,我认为这最有效。如果您正在进行更新/插入/删除,请使用第一种方法。
  2. 当您需要在完全不同的数据源(可能是数据库中的userid和employeeid,以及Active Directory中的显示名称,站点位置等)之间创建一些逻辑对象时,这非常有用。
  3. 可以通过这种方式进行更新,但您必须做更多的工作来分离您的商品并正确更新所有内容。
  4. 总之,我建议使用第一种方法,除非发生以下情况:您需要一个跨越数据存储的逻辑对象(单独的数据库源),或者您需要快速只读访问(例如DropS的ItemSource绑定) - 下单列表)。

    将排序和过滤逻辑卸载到服务器,即使以在内存中加载的其他实体为代价,以便客户可以保持快速支付红利。在CollectionViewSource或其他东西中使用本地排序可以做同样的事情,但只有其中一些可以真正开始降低您的应用程序速度。