DTO'

时间:2018-03-11 14:51:26

标签: c# angular entity-framework breeze

我正在为大型企业,面向数据的Angular 5应用程序评估Breeze.Js,以便利用vanilla Angular框架中缺少的以下功能:

  • 客户端数据存储
  • 客户端模型状态跟踪
  • 客户端模型验证规则
  • 批量数据持久性(保存所有实体的SaveChanges()方法)。

出于测试目的,我在ASP.NET WebApi + EntityFramework服务器端编写了以下简单的BreezeController:

    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [BreezeController]
    public class PeopleController : ApiController
    {
        private AdventureWorksDbContext db = new AdventureWorksDbContext();


        #region "Breeze"

        readonly EFContextProvider<AdventureWorksDbContext> _contextProvider =
        new EFContextProvider<AdventureWorksDbContext>();

        // ~/breeze/todos/Metadata 
        [HttpGet]
        public string Metadata()
        {
            return System.Text.Encoding.UTF8.GetString(AdventureWorks.WebApi.Properties.Resources.WebApiMetadata); 
        }

        // ~/breeze/todos/Todos
        // ~/breeze/todos/Todos?$filter=IsArchived eq false&$orderby=CreatedAt 
        [HttpGet]
        public IQueryable<PersonDTO> GetPeople()
        {
            return db.People.ProjectTo<PersonDTO>();
        }

        // ~/breeze/todos/SaveChanges
        [HttpPost]
        public SaveResult SaveChanges(Newtonsoft.Json.Linq.JObject saveBundle)
        {
            return _contextProvider.SaveChanges(saveBundle);
        }

        #endregion
}

正如您在我的示例中所看到的(它使用AdventureWorks DB),我已做了以下修改: 1)&#34; GetPeople()&#34; endpoint返回DTO的可查询对象(&#34; ProjectTo&#34;扩展由Automapper提供)。我需要这样做,以便为客户端以可用的方式塑造模型,避免递归,深入了解模式,大字段序列化等等。

2)&#34;元数据()&#34; endpoint返回表示DTO类元数据的字符串资源。我使用&#34; PocoMetadata&#34;来构建它。 &#34; Breeze工具套件的工具&#34; (https://github.com/Breeze/breeze.tooling)。这是必要的,因为只要我使用DTO而非EF POCO类,我就无法返回_contextProvider.Metadata()结果。

现在,如果在我的Angular 5客户端中发出如下所示的ODATA查询,我可以看到executeQuery()方法确实有效:

export class BreezeDataStoreComponent implements OnInit {

private _em: EntityManager;

  constructor() {

    this._em = new EntityManager({
      serviceName: 'http://localhost:31328/breeze/People'
    });
   }

  ngOnInit() {

    const query = EntityQuery.from('GetPeople')
                           .where('FirstName', FilterQueryOp.StartsWith, 'F')
                           .orderBy('LastName', true);
    this._em.executeQuery(query).then(res => {

      // Here i can get all People instances.
      // Now i try to get the first, edit the name and saveChanges.
      (res.results[0] as any).FirstName = 'Franklino';

      this._em.saveChanges().then(saveResult => {
          const test = saveResult.entities;
      });
    });
  }    
}

不幸的是SaveChanges()会出现问题。 当Angular客户端调用该方法时,在我的服务器端,我收到以下错误:

  

System.InvalidOperationException:Sequence不包含匹配项   元件

我认为这是因为我通过EF上下文提供程序调用SaveChanges(),传递一个引用DTO而不是POCO类的JObject bundle。

所以我的问题是:

是否可以使用DTO&#39;来使用BreezeJs查询和批量持久性(SaveChanges()方法)?在以数据为中心的大型企业应用程序中,这是一个非常普遍的需求,因为我认为在WebApi上暴露EF POCO是一种不好的做法。

我应该依赖于响应POST \ PUT \ DELETE HTTP动词的经典WebApi吗?在这种情况下,如何配置Breeze客户端以联系这些端点而不是&#34; SaveChanges&#34;什么时候保持数据?

如果Breeze不适合这种需求,还有其他技术可以提供上述4点吗?

非常感谢。

1 个答案:

答案 0 :(得分:1)

要使SaveChanges与您的DTO一起使用,您需要

  1. 编写您自己的方法以解压缩JObject saveBundle
  2. 使用BeforeSaveChanges方法修改DTO字典,并将其替换为EF理解的实体。
  3. 2号似乎是更好的选择。如果实体与DTO之间没有1:1的匹配,则在进行映射时需要一些逻辑。