基于查询ASP.NET从模型返回列表的一部分

时间:2017-03-01 11:36:32

标签: c# asp.net asp.net-mvc entity-framework

我有以下model

    public class Vendor
        {
            public int Id { get; set; }

            [Required]
            public string Name { get; set; }

            [Display(Name = "Date of Birth")]
            public DateTime? BirthDate { get; set; }

            [Required]
            [EmailAddress]
            public string Email { get; set; }

            [MinLength(10)]
            public string Telephone { get; set; }

            public string Notes { get; set; }

            public Currency Currency { get; set; }
            [Display(Name = "Currency")]
            public int? CurrencyId { get; set; }

            public List<Translation> Translations { get; set; }

            public byte? Rating { get; set; } 
        }

我正在实现一个api,它将返回数据库中的所有供应商。问题是我需要在返回的JSON对象中包含符合某些规范的Translations。 现在,我的API Controller看起来像这样:

public IEnumerable<VendorDto> GetVendors(string sourceLanguage = null, string targetLanguage = null, string service = null)
        {
            var vendorsQuery = _context.Vendors
                .Include(v => v.Translations.Select(t => t.SourceLanguage))
                .Include(v => v.Translations.Select(t => t.TargetLanguage))
                .Include(v => v.Translations.Select(t => t.Service))
                .Include(v => v.Currency);

            var result = vendorsQuery.ToList();

            IEnumerable<Translation> filteredTranslationsResults;

            if (!String.IsNullOrWhiteSpace(sourceLanguage))
            {
                if (!String.IsNullOrWhiteSpace(targetLanguage))
                {
                    if (!String.IsNullOrWhiteSpace(service))
                    {
                        filteredTranslationsResults = vendorsQuery
                            .SelectMany(v => v.Translations)
                            .Where(t => t.SourceLanguage.Name == sourceLanguage)
                            .Where(t => t.TargetLanguage.Name == targetLanguage)
                            .Where(t => t.Service.Name == service);
                        vendorsQuery = vendorsQuery
                            .Where(v => v.Translations.Intersect(filteredTranslationsResults).Any());
                    }
                    else
                    {
                        filteredTranslationsResults = vendorsQuery
                            .SelectMany(v => v.Translations)
                            .Where(t => t.SourceLanguage.Name == sourceLanguage)
                            .Where(t => t.TargetLanguage.Name == targetLanguage);
                        vendorsQuery = vendorsQuery
                            .Where(v => v.Translations.Intersect(filteredTranslationsResults).Any());
                    }
                }
                else
                {
                    filteredTranslationsResults = vendorsQuery
                            .SelectMany(v => v.Translations)
                            .Where(t => t.SourceLanguage.Name == sourceLanguage);
                    vendorsQuery = vendorsQuery
                        .Where(v => v.Translations.Intersect(filteredTranslationsResults).Any());
                }
            }

            return vendorsQuery
                .ToList()
                .Select(Mapper.Map<Vendor, VendorDto>);
        }

所以基本上我需要返回所有Vendors source/target language servicevendors作为参数传递,并且translations返回,我需要有只有source/target languageserviceController的{​​{1}}。对于我当前的Vendor实施,如果它在Translations列表中找到translation,我正在寻找的Vendor,则返回translations与他所有的Intersect,因为Vendor只是说它是真的然后得到所有。 我需要更改什么,以便返回的对象(translation)仅包含我正在寻找的Translation

更新public class Translation { public int Id { get; set; } public Language SourceLanguage { get; set; } [Display(Name = "Source Language")] public int SourceLanguageId { get; set; } public Language TargetLanguage { get; set; } [Display(Name = "Target Language")] public int TargetLanguageId { get; set; } public Service Service { get; set; } [Display(Name = "Service")] public int ServiceId { get; set; } public int Price { get; set; } public UnitMeasure UnitMeasure { get; set; } [Display(Name = "Unit Measure")] public int UnitMeasureId { get; set; } } 型号:

JPA 2.2

1 个答案:

答案 0 :(得分:2)

嗯,这可能很糟糕,但根据你的模型,这是我提出的一件事:

但请注意,根据您拥有的供应商和翻译的数量,在应用谓词之前调用tolist可能会更快(例如,如果您的记录低于100K,则可能会更快地将所有这些记录拉下来。)< / p>

public IEnumerable<VendorDto> GetVendors(string sourceLanguage = null, string targetLanguage = null, string service = null)
        {
            var vendorsQuery = _context.Vendors
                .Include(v => v.Translations.Select(t => t.SourceLanguage))
                .Include(v => v.Translations.Select(t => t.TargetLanguage))
                .Include(v => v.Translations.Select(t => t.Service))
                .Include(v => v.Currency)
                // consider adding a .ToList() right here based on how many records you have


                Expression<Func<Translation, bool>> sourceLanguagePredicate = z => z.SourceLanguage.Name == sourceLanguage;
                Expression<Func<Translation, bool>> targetLanguagePredicate = z => z.TargetLanguage.Name == targetLanguage;
                Expression<Func<Translation, bool>> servicePredicate = z => z.Service.Name == service;

                var hasSource = !string.IsNullOrWhiteSpace(sourceLanguage);
                var hasTarget = !string.IsNullOrWhiteSpace(targetLanguage);
                var hasService = !string.IsNullOrWhiteSpace(service);
                if(hasSource)
                {
                    vendorsQuery = vendorsQuery.Where(x => x.Translations.AsQueryable().Any(sourceLanguagePredicate));
                }

                if(hasTarget)
                {
                    vendorsQuery = vendorsQuery.Where(x => x.Translations.AsQueryable().Any(targetLanguagePredicate));
                }

                if(hasService)
                {
                    vendorsQuery = vendorsQuery.Where(x => x.Translations.AsQueryable().Any(servicePredicate));
                }

                var vendors = vendorsQuery.ToList();

                foreach(var vendor in vendors)
                {
                    if(hasSource)
                    {           
                        vendor.Translations = vendor.Translations.Where(sourceLanguagePredicate).ToList();
                    }

                    if(hasTarget)
                    {           
                        vendor.Translations = vendor.Translations.Where(targetLanguagePredicate).ToList();
                    }

                    if(hasService)
                    {           
                        vendor.Translations = vendor.Translations.Where(servicePredicate).ToList();
                    }
                }

                return vendors.Select(Mapper.Map<Vendor, VendorDto>);
        }