简体   繁体   English

如何通过webapi2将扁平列表返回到breezejs?

[英]How to get a flattened list back to breezejs through webapi2?

I have been struggling with this for a week now. 我一直在努力这一周。 I have a table of Person and Company in the DB. 我在DB中有一个人员公司的表。 However, there is also a joiner Table of CompanyPerson which has some extra properties like IsPrimaryPerson . 但是,还有一个公司表的CompanyPerson ,它有一些额外的属性,如IsPrimaryPerson Great. 大。 Works and all that stuff if I load each thing on it's own into breezejs. 如果我将每件东西加载到breezejs中,那就可以工作了。

So the problem is that I want to create a list of Persons, but flattened with Companies, like a left outer join, so that I also get each person and company on one line and also include those who do not have a company. 所以问题在于我想创建一个人员列表,但是像公司一样扁平化,例如左外连接,这样我也可以让每个人和公司在一条线上,也包括那些没有公司的人。

This linq statement in C# gives me that list, I used linqPad to get it working. 这个在C#中的linq语句给了我那个列表,我使用linqPad来实现它。 It's a left outer join sql equivlant. 这是一个左外连接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
        }

Great. 大。 However what I don't know, is how to get a list like this back to breezejs via the webapi2. 但是我不知道的是,如何通过webapi2将这样的列表返回到breezejs。 Issue one is that the linq returns an anonymnous object. 问题一是linq返回一个匿名对象。 I've tried creating like a ContactPerson object and having properties for Person and Company but I don't know how to get back to breeze since it's not part of the metadata. 我尝试创建类似于ContactPerson对象并具有Person和Company的属性,但我不知道如何回到微风,因为它不是元数据的一部分。

Controller, this doesn't work for various reasons depending what I try and do. 控制器,这取决于我尝试和做的各种原因。 From "The entity or complex type 'SiteTrackerModel.ContactPerson' cannot be constructed in a LINQ to Entities query" to other problems. 从“实体或复杂类型'SiteTrackerModel.ContactPerson'不能在LINQ to Entities查询中构造”到其他问题。 Just have it here to show you what I'm trying in a way. 只是在这里向你展示我正在尝试的方式。

    [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;

    }

BreezeJs Call in Angular BreezeJs呼叫Angular

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

Here are the classes/tables I'm trying to flatten and return to breeze. 这是我试图压扁并回归微风的类/表。 I've trimmed down most of the properties 我已经削减了大部分属性

Person.cs (Person Table in Edmx/db) Person.cs(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) CompanyPerson.cs(Edmx / db中的CompanyPerson表)

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) Company.cs(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; }
}

I even tried creating a view in sql that gave me the data, but I can't get Breezejs to figure out what it is but that was just a means to the goal above. 我甚至尝试在sql中创建一个给我数据的视图,但我不能让Breezejs弄清楚它是什么,但这只是上述目标的一种方法。 A flattened list of people and companies even if they don't have a company. 即使没有公司,人员和公司也会被列为扁平化列表。

You can send projection data to BreezeJS and turn them into a custom EntityType you've defined on the client. 您可以将投影数据发送到BreezeJS并将它们转换为您在客户端上定义的自定义EntityType You can't expect that ContactPerson type to show up in metadata from the server that has been generated by Entity Framework; 您不能指望ContactPerson类型显示在Entity Framework生成的服务器的元数据中; it's a DTO and not part of the model that EF knows about. 它是一个DTO,而不是EF所知道的模型的一部分。

That shouldn't stop you from defining ContactPerson on your Breeze client. 这不应该阻止你在Breeze客户端上定义ContactPerson Learn about how to create client-side metadata in the docs. 了解如何在文档中创建客户端元数据

It's worth noting that you do not have to define all of your metadata on the client to take advantage of this feature. 值得注意的是,您不必在客户端上定义所有元数据以利用此功能。 Just add this ContactPerson type. 只需添加此ContactPerson类型即可。

The next trick is getting BreezeJS to realize that your projection data should be transformed into ContactPerson entity on the client. 下一个技巧是让BreezeJS意识到您的投影数据应该转换为客户端上的ContactPerson实体。

Breeze won't recognize the anonymous type data by default. 默认情况下,Breeze无法识别匿名类型数据。 You can give it some help with the toType query clause . 您可以为toType查询子句提供一些帮助。 You can uncomment that clause in your query after you have defined the type in your client metadata . 在客户端元数据中定义类型后 ,可以在查询中取消注释该子句。

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

You won't need the toType clause if you project into a server-side ContactPerson type and connect the dots between the "PersonsFlattened" endpoint and your custom client-side ContactPerson type in metadata. 如果您投影到服务器端的ContactPerson类型并连接“PersonsFlattened”端点和元数据中的自定义客户端ContactPerson类型之间的点,则不需要toType子句。 I think I'd rename that endpoint "ContactPersons" for consistency. 我想我会重命名该端点“ContactPersons”以保持一致性。

NB : I trust you realize that you've defined read-only types. 注意 :我相信你已经意识到你已经定义了只读类型。 Breeze doesn't know that so if you make changes to a ContactPerson entity in BreezeJS, the manager will try to save it. Breeze不知道如此,如果您在BreezeJS中对ContactPerson实体进行更改,管理器将尝试保存它。 Your save attempt will throw on the server unless you catch the incoming change on and do something marvelous with it, perhaps in a BeforeSaveEntity method. 您的保存尝试将抛出服务器,除非您捕获传入的更改并使用它做一些了不起的事情,可能是在BeforeSaveEntity方法中。

The exception "The entity or complex type 'SiteTrackerModel.ContactPerson' cannot be constructed in a LINQ to Entities query" is related to how the class ContactPerson is declared. “无法在LINQ to Entities查询中构造实体或复杂类型'SiteTrackerModel.ContactPerson'”与例如如何声明类ContactPerson有关。 LINQ to entity can only construct pur Data Transfert Object : class containing only public properties with trivial getter and setter and without constructor. LINQ to entity只能构造pur Data Transfert Object :只包含具有普通getter和setter且没有构造函数的公共属性的类。

Check the ContactPerson class definition. 检查ContactPerson类定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM