如何通过webapi2将一个扁平的列表返回给breezejs

本文关键字:列表 返回 breezejs 一个 webapi2 何通过 | 更新日期: 2023-09-27 18:10:31

我已经为此挣扎了一个星期了。我在DB中有一个PersonCompany的表。然而,也有一个joiner Table CompanyPerson,它有一些额外的属性,如IsPrimaryPerson。太好了。工作和所有的东西,如果我把每个东西自己加载到breezejs。

所以问题是,我想创建一个Persons列表,但是用Companies平面化,就像左外连接一样,这样我也可以将每个人和公司放在一行上,还包括那些没有公司的人。

c#中的linq语句给了我这个列表,我用linqPad让它工作。这是一个左外连接sql等同。

  from p in Person
    join cp in CompanyPerson
     on p.Id equals cp.PersonId
     into companyPersonGroups
     from cp in companyPersonGroups.DefaultIfEmpty()
    select new {
        Person = p,
        CompanyPerson = cp,
        Company = cp.Company
        }

好了。然而我不知道的是,如何通过webapi2将这样的列表返回给breezejs。第一个问题是linq返回一个匿名对象。我试过创建像ContactPerson对象和有属性的人和公司,但我不知道如何回到微风,因为它不是元数据的一部分。

控制器,这不起作用的各种原因取决于我尝试做什么。来自"实体或复杂类型"SiteTrackerModel。ContactPerson'不能在LINQ到实体查询中构造',以解决其他问题。我把它放在这里,让你看看我在做什么。

    [BreezeQueryable(MaxExpansionDepth = 3)]
    [HttpGet]
    public IQueryable<ContactPerson> PersonsFlattened()
    {
        //return _contextProvider.QueryAll<Person>();
        var contacts = from person in _contextProvider.QueryAll<Person>()
                       join companyPerson in CompanyPersons() on person.Id equals companyPerson.PersonId into companyPersonGroups
                       from companyPerson in companyPersonGroups.DefaultIfEmpty()
                       select new ContactPerson()
                       {
                           FirstName = person.FirstName,
                           IsPrimaryPerson = companyPerson.IsPrimaryPerson,
                           CompanyName = companyPerson.Company.Name
                       };
        return contacts;
    }

Angular中的BreezeJs调用

return EntityQuery.from("PersonsFlattened")
                 //.toType("ContactPerson")
                 .orderBy(orderBy)
                 .using(self.manager).execute()
                 .then(querySucceeded, self._queryFailed);

这里是类/表,我试图平,并返回到微风。我已经删减了大部分属性

Person.cs (Person Table in Edmx/db)

public partial class Person
{
    public Person()
    {
        this.Companies = new HashSet<CompanyPerson>();
    }
    public int Id { get; set; }
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual ICollection<CompanyPerson> Companies { get; set; }
}

CompanyPerson.cs (CompanyPerson Table in Edmx/db)

public partial class CompanyPerson
{
    public int PersonId { get; set; }
    public int CompanyId { get; set; }
    public bool IsPrimaryPerson { get; set; }
    public virtual Company Company { get; set; }
    public virtual Person Person { get; set; }
}

Company.cs (Company Table in edmx/db)

public partial class Company
{
    public Company()
    {
        this.Projects = new HashSet<Project>();
        this.PhoneNumbers = new HashSet<CompanyPhoneNumber>();
        this.Addresses = new HashSet<CompanyAddress>();
        this.Persons = new HashSet<CompanyPerson>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<CompanyPerson> Persons { get; set; }
}

我甚至试着在sql中创建一个视图,给了我数据,但我不能让Breezejs弄清楚它是什么,但这只是实现上述目标的一种手段。一个扁平的人员和公司名单,即使他们没有公司。

如何通过webapi2将一个扁平的列表返回给breezejs

您可以将投影数据发送到BreezeJS并将它们转换为您在客户端上定义的自定义EntityType。你不能期望ContactPerson类型显示在元数据从服务器已由实体框架生成;这是一个DTO,而不是EF所知道的模型的一部分。

这不应该阻止您在您的Breeze客户端上定义ContactPerson。了解如何在文档中创建客户端元数据。

值得注意的是,不必在客户端上定义所有元数据来利用此特性。只要添加这个ContactPerson类型。

下一个技巧是让BreezeJS意识到你的投影数据应该在客户端转换为ContactPerson实体。

默认情况下,Breeze不会识别匿名类型数据。您可以使用toType查询子句为它提供一些帮助。在客户端元数据中定义了类型之后,可以取消查询中的该子句的注释。

return EntityQuery.from("PersonsFlattened")
       .toType("ContactPerson") // Should work after defining ContactPerson on client
       .orderBy(orderBy)
       .using(self.manager).execute()
       .then(querySucceeded, self._queryFailed);

如果您投射到服务器端ContactPerson类型,并将"personsflat"端点与元数据中自定义的客户端ContactPerson类型之间的点连接起来,则不需要toType子句。为了保持一致性,我想我应该将端点重命名为"ContactPersons"。

注意::我相信您已经意识到您已经定义了只读类型。Breeze不知道这一点,所以如果你在BreezeJS中更改了ContactPerson实体,管理员将尝试保存它。您的保存尝试将在服务器上抛出,除非您捕捉到传入的更改并对它做一些了不起的事情,也许是在BeforeSaveEntity方法中。

例外"实体或复杂类型" SiteTrackerModel。与类ContactPerson的声明方式有关。LINQ到实体只能构造一个数据传输对象:类,该类只包含带有普通getter和setter的公共属性,没有构造函数。

检查ContactPerson类定义