使用 Odata 查询基于 EF 的 DTO

2023-12-27

我有一个 ASP.NET Core Web API 设置,其中包含 SQL Server 数据库和 EF 数据模型。

版本:

  • EF:Microsoft.EntityFrameworkCore 5.0.0-预览版.7.20365.15
  • OData:Microsoft.AspNetCore.OData 7.4.1
  • .Net核心3.1

问题是:我无法使用过滤器,在扩展中选择(嵌套扩展)。 OData 未向 SQL Server Profiler 上看到的 SQL 查询的 where 条件添加筛选器的示例 URL:

https://localhost:44327/odata/clientcontract?$expand=ContactsInfo($filter=value eq '100003265')

https://localhost:44327/odata/clientcontract?$expand=Documents($filter=documentnnumber eq '100003265')

这些是我的数据库优先实体模型:

public partial class ClientRef
{
    public ClientRef()
    {
        Addresses = new HashSet<Address>();
        Assets = new HashSet<Asset>();
        ClientContactInfoComps = new HashSet<ClientContactInfoComp>();
        ClientRelationCompClient1Navigations = new HashSet<ClientRelationComp>();
        ClientRelationCompClient2Navigations = new HashSet<ClientRelationComp>();
        Clients = new HashSet<Client>();
        CommentComps = new HashSet<CommentComp>();
        Companies = new HashSet<Company>();
        Documents = new HashSet<Document>();
        PhysicalPeople = new HashSet<PhysicalPerson>();
    }

    [Column("Inn")]
    public int Id { get; set; }

    public virtual ICollection<Address> Addresses { get; set; }
    public virtual ICollection<Asset> Assets { get; set; }
    public virtual ICollection<ClientContactInfoComp> ClientContactInfoComps { get; set; }
    public virtual ICollection<ClientRelationComp> ClientRelationCompClient1Navigations { get; set; }
    public virtual ICollection<ClientRelationComp> ClientRelationCompClient2Navigations { get; set; }
    public virtual ICollection<Client> Clients { get; set; }
    public virtual ICollection<CommentComp> CommentComps { get; set; }
    public virtual ICollection<Company> Companies { get; set; }
    public virtual ICollection<Document> Documents { get; set; }
    public virtual ICollection<PhysicalPerson> PhysicalPeople { get; set; }
}

public partial class Document
{
    public int Id { get; set; }
    public string DocumentNumber { get; set; }
    public int DocumentType { get; set; }
    public int Inn { get; set; }
    public DateTime ValidFrom { get; set; }
    public DateTime ValidTo { get; set; }
    public DateTime? DocumentExpireDate { get; set; }

    public virtual ClientRef InnNavigation { get; set; }
}

public partial class ClientContactInfoComp
{
    public int Id { get; set; }
    public int Inn { get; set; }
    public int ContactInfoId { get; set; }
    public int? Point { get; set; }
    public DateTime ValidFrom { get; set; }
    public DateTime ValidTo { get; set; }

    [ForeignKey("ContactInfoId")]
    public  ContactInfo ContactInfo { get; set; }
    public virtual ClientRef InnNavigation { get; set; }
}

public partial class ContactInfo
{
    public ContactInfo()
    {
        CallHistories = new HashSet<CallHistory>();
        ClientContactInfoComps = new HashSet<ClientContactInfoComp>();
        CommentComps = new HashSet<CommentComp>();
    }

    public int Id { get; set; }
    public int? Type { get; set; }
    public string Value { get; set; }

    public virtual ICollection<CallHistory> CallHistories { get; set; }
    public virtual ICollection<ClientContactInfoComp> ClientContactInfoComps { get; set; }
    public virtual ICollection<CommentComp> CommentComps { get; set; }
}

public partial class CommentComp
{
    public int Id { get; set; }
    public int Inn { get; set; }
    public int? CommentId { get; set; }
    public int? ContactId { get; set; }

    public virtual Comment Comment { get; set; }
    public virtual ContactInfo Contact { get; set; }
    public virtual ClientRef InnNavigation { get; set; }
}

public partial class Comment
{
    public Comment()
    {
        CommentComps = new HashSet<CommentComp>();
    }

    public int Id { get; set; }
    public string Text { get; set; }
    public DateTime? CreateTimestamp { get; set; }
    public string Creator { get; set; }

    public virtual ICollection<CommentComp> CommentComps { get; set; }
}

这些是我的 DTO:

[DataContract]
public class ClientContract
{
    public ClientContract()
    {
        ContactsInfo = new List<ContactInfoContract>();
        Documents = new List<DocumentContract>();
        Relations = new List<RelationContract>();
        ClientComment = new CommentContract();
    }

    [DataMember(Name = "INN")]
    [Key]
    public int INN { get; set; }

    [DataMember(Name = "validfrom")]
    public DateTime ValidFrom { get; set; }

    [DataMember(Name = "validto")]
    public DateTime ValidTo { get; set; }

    [DataMember(Name = "clienttype")]
    public ClientType ClientType { get; set; }

    [DataMember(Name = "companyname")]
    public string CompanyName { get; set; }

    [DataMember(Name = "firstname")]
    public string FirstName { get; set; }

    [DataMember(Name = "lastname")]
    public string LastName { get; set; }

    [DataMember(Name = "fathername")]
    public string FatherName { get; set; }

    [DataMember(Name = "pinnumber")]
    public string PinNumber { get; set; }

    [DataMember(Name = "birthdate")]
    public DateTime? BirthDate { get; set; }

    [DataMember(Name = "positioncustom")]
    public string PositionCustom { get; set; }

    [DataMember(Name = "position")]
    public int Position { get; set; }

    [DataMember(Name = "monthlyincome")]
    public decimal MonthlyIncome { get; set; }

    [DataMember(Name = "clientcomment")]
    public CommentContract ClientComment { get; set; }        

    [DataMember(Name = "contactsinfo")]
    public List<ContactInfoContract> ContactsInfo { get; set; }
    
    [DataMember(Name = "documents")]
    [ForeignKey("Documents")]
    public List<DocumentContract> Documents { get; set; }

    [DataMember(Name = "relations")]
    public List<RelationContract> Relations { get; set; }
}

public class DocumentContract
{
    [Key]
    public int Id { get; set; }

    [DataMember(Name = "documentNumber")]
    public string documentNumber { get; set; }

    [DataMember(Name = "documentType")]
    public int documentType { get; set; }

    [DataMember(Name = "documentexpiredate")]
    public DateTime? documentExpireDate { get; set; }
}

[DataContract]
public class ContactInfoContract
{
    public ContactInfoContract()
    {
        ContactComment = new CommentContract();
    }

    [Key]
    public int Id { get; set; }

    [DataMember(Name = "type")]
    public int Type { get; set; }

    [DataMember(Name = "value")]
    public string Value { get; set; }

    [DataMember(Name = "contactComment")]
    public CommentContract ContactComment { get; set; }
}

public class CommentContract
{
    [DataMember(Name = "Text")]
    public string Text { get; set; }

    [DataMember(Name = "creator")]
    public string Creator { get; set; }
}

在 DTO 中没有关系模型。例如:在EF中,有一个ClientContactInfoComp模型,它连接ClientRefs和ContactInfo模型,但在DTO中,ClientContract是直接用ContactInfoContract引用的。

Startup.cs 中的模型生成器

private  IEdmModel GetEdmModel()
{
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<ClientContract>("ClientContract").EntityType.HasKey(x => x.INN).Name = "ClientRef";
        builder.EntitySet<DocumentContract>("DocumentContract");
        builder.EntitySet<ContactInfoContract>("ContactInfoContracts").EntityType.HasKey(x => x.Id);

        return builder.GetEdmModel();
}

public class ClientContractController : ControllerBase
{
    [EnableQuery(MaxExpansionDepth = 10)]
    public IQueryable<ClientContract> Get()
    {
        var clientRefs = _context.ClientRefs
                         .Include(x => x.Clients.Where(x => x.ValidFrom < DateTime.Now && x.ValidTo > DateTime.Now))
                         .Include(x => x.PhysicalPeople.Where(x => x.ValidFrom < DateTime.Now && x.ValidTo > DateTime.Now))
                         .Include(x => x.Companies.Where(x => x.ValidFrom < DateTime.Now && x.ValidTo > DateTime.Now))
                         .Include(x => x.Documents.Where(x => x.ValidFrom < DateTime.Now && x.ValidTo > DateTime.Now))
                         .Include(x => x.ClientContactInfoComps.Where(x => x.ValidFrom < DateTime.Now && x.ValidTo > DateTime.Now))
                         .ThenInclude(x => x.ContactInfo)
                         .Include(x => x.Assets.Where(x => x.ValidFrom < DateTime.Now && x.ValidTo > DateTime.Now));

        List<ClientContract> contracts = new List<ClientContract>();

        foreach (var clientRef in clientRefs)
        {
            ClientContract clientContract = new ClientContract() { INN = clientRef.Id };

            foreach(var c in clientRef.Clients)
            {
                clientContract.ClientType = (ClientType) c.ClientType;
            }

            foreach (var pp in clientRef.PhysicalPeople)
            {
                clientContract.FirstName = pp.FirstName;
                clientContract.LastName = pp.LastName;
            }

            foreach (var comp in clientRef.Companies)
            {
                clientContract.CompanyName = comp.CompanyName;
            }

            foreach (var doc in clientRef.Documents)
            {
                clientContract.Documents.Add(new DocumentContract()
                {
                    documentNumber = doc.DocumentNumber,
                    documentExpireDate = doc.DocumentExpireDate,
                    documentType = doc.DocumentType
                    
                });
            }

            foreach (var comp in clientRef.ClientContactInfoComps)
            {
                clientContract.ContactsInfo.Add(new ContactInfoContract
                {
                    Type = comp.ContactInfo.Type.Value,
                    Value = comp.ContactInfo.Value
                });
            }

            contracts.Add(clientContract);
        }

        return contracts.AsQueryable();
    }
}

是的,我从以下链接得到结果: https://localhost:44327/odata/clientcontract

https://localhost:44327/odata/clientcontract?$filter=Id eq 4

https://localhost:44327/odata/clientcontract?$expand=documents,contactsinfo

Startup.cs



   public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();//.AddNewtonsoftJson(); ;
        services.AddDbContext<DbContext>(options =>
        options.UseSqlServer("connectionstring"));
        services.AddOData();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            //endpoints.EnableDependencyInjection();
            endpoints.Expand().Select().Filter().OrderBy().Count().MaxTop(10);
            endpoints.MapODataRoute("odata", "odata", GetEdmModel());
        });

        
    }

    private  IEdmModel GetEdmModel()
    {
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<ClientContract>("ClientContract").EntityType.HasKey(x => x.INN).Name = "ClientRef";
        builder.EntitySet<DocumentContract>("DocumentContract");
        builder.EntitySet<ContactInfoContract>("ContactInfoContracts").EntityType.HasKey(x => x.Id);
        
        return builder.GetEdmModel();
    }

    
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Odata 查询基于 EF 的 DTO 的相关文章

随机推荐

  • 如何在 Android 模拟器中运行 YouTube 视频

    我制作了一个程序 在列表视图中获取 YouTube 视频列表 并且还实现了 onClick 来源 我遵循了有关如何使用 youtube gdata 的教程 使用来自 youtube 的视频和 onclick 填充列表视图 源代码可在以下位置
  • RestTemplate 与正文一起获取

    如何使用休息模板来获取身体 基于以下问题 通过 JSON 格式的 RestTemplate 进行 POST 请求 https stackoverflow com questions 4075991 post request via rest
  • Fabric Javascript SDK 和 Hyperledger Composer 之间有哪些功能差异?

    除了 Composer 使原型业务网络的部署和测试变得更加容易 以及我们不需要了解 golang 来开发链代码这一事实之外 这些接口提供的功能有何差异 可能会导致人们选择其中之一另一个 这篇文章或许可以为您提供所需的答案 https blo
  • 高精度事件定时器

    include target h include xcp h include LocatedVars h include osek h This task is activated every 10ms long OSTICKDURATIO
  • NSJSONSerialization 不创建可变容器

    这是代码 NSError parseError NSMutableArray listOfObjects NSJSONSerialization JSONObjectWithData dataUsingEncoding NSUTF8Stri
  • 基于标记的 Google 地图居中

    我想根据动态加载的标记将我的 Google 地图居中 我已经看到了 边界 的使用并尝试实现 适合边界 但我无法将其正确应用到我的地图上 这是代码 var MapStart new google maps LatLng 41 664723 9
  • rake 任务中 open-uri 出现 404 错误...是什么原因造成的?

    我有一个 rake 任务 它从 API 获取 JSON 数据 解析它 并将其保存到数据库 task embedly gt environment do require json require uri require open uri Vi
  • PHP - 获取函数的所有参数(甚至是可选参数)

    我想从函数中获取所有参数 传递或未传递 Example 如果我打电话 test func get args foo 10 var dump test 我只会有一个数组 0 gt 10 即使我没有传递可选参数 我怎样才能获得它的值 我知道fu
  • 在 EAR 中的多场战争中共享公共 jsp

    我们有一个包含 13 个模块的大型应用程序 根据客户需求 我们应该能够部署核心模块 客户特定模块 我们计划将应用程序分成多场战争 现在的问题是我们有一些常见的jsp 例如header jsp error jsp等 有什么方法可以让我们将常见
  • Flex 可重入以用户特定状态启动

    Flex 设置YY STATE to INITIAL默认情况下 当yyscan t叫做 我正在尝试制作一个可重入扫描仪 可以从特定于用户的状态而不是 INITIAL 这是案例 comment start not passed into fl
  • 我可以重新调整旧的提交吗?

    我刚刚开始使用 git Rebase 是很棒的东西 我应该在之前的特定案例中使用它 为了清晰的提交 是否有一种完全可以接受的方法来重新调整旧提交的基础 您应该只对尚未推送到上游的提交执行此操作 也就是说 我发现最容易使用git rebase
  • false 的未定义方法 `+@':FalseClass (NoMethodError) ruby

    def next prime number last known prime while true last known prime found factor false ERROR for i in 1 last known prime
  • 如何从库中启动 Android 应用程序中的 Activity

    我在 Android Studio 中有一个 Android 应用程序 我已经在应用程序中添加了一个库 按钮 视图和活动在库中定义 当我单击按钮时 我需要导航到应用程序中定义的活动 通常 为了导航到另一个页面 我们使用意图 如下所示 Int
  • 如何本地化 iOS info.plist 文件中的字符串?

    As you might know the iOS 8 requires NSLocationWhenInUseUsageDescription key for using user s location I have added this
  • 有没有办法将外部 Javascript 作为 Jasmine 的来源?

    我正在尝试配置 jasmine yml 使用 jasmine gem 以使用 Google API 提供的 JQuery 而不是将其本地下载到我的服务器 IE src files ajax googleapis com ajax libs
  • Lubuntu 中的多个光标 - Shift + Alt + 箭头(向上/向下)

    在使用时 多光标功能对我来说非常有效Xubuntu https en wikipedia org wiki Xubuntu 我最近安装了Lubuntu https en wikipedia org wiki Lubuntu非常失望的是 我意
  • std::vector::iterator 可以简单地是 T* 吗?

    简单的理论问题 简单的指针是否是有效的迭代器类型std vector 对于其他容器 例如列表 地图 这是不可能的 但是对于std vector所保存的数据保证是连续的 所以我认为没有理由不这样做 据我所知 一些实现 例如 Visual St
  • html 重置后,javascript 事件丢失

    我遇到过这样一种情况 div 的 html 内容有时会更改为其他内容 然后又更改回来 一些 jquery ui 控件行为不当 我已将问题简化为以下代码片段 它基本上表明与按钮关联的事件处理程序不再触发 我假设这些在它们消失后的某个时刻被垃圾
  • phoneGap (Cordova) 内部如何工作,特定于 iOS

    我已经开始为多个平台开发 html 应用程序 我最近听说了 Cordova 2 0 PhoneGap 从那时起我就很好奇这座桥是如何工作的 经过大量代码检查后 我发现 Exec js 是 JS gt Native 调用发生的代码 execX
  • 使用 Odata 查询基于 EF 的 DTO

    我有一个 ASP NET Core Web API 设置 其中包含 SQL Server 数据库和 EF 数据模型 版本 EF Microsoft EntityFrameworkCore 5 0 0 预览版 7 20365 15 OData