How to write Unit test cases for Linq joins for Get API in DotNet - linq

public LoginUserDTO GetUserDetailsById(int id)
{
var result = _loginRepository.FindByQueryable(x => x.DeleteFlag == false && x.Id == id)
.Join(_loginStatusRepository.FindByQueryable(x => x.DeleteFlag == false),
login => login.LoginStatusId,
loginStatus => loginStatus.Id,
(login, loginStatus) => new { login, loginStatus })
.Join(_loginHasRoleRepository.FindByQueryable(x => x.DeleteFlag == false),
loginAndloginStatus => loginAndloginStatus.login.Id,
loginHasRole => loginHasRole.LoginId,
(loginAndloginStatus, loginHasRole) => new { loginAndloginStatus, loginHasRole })
.Join(_loginHasPhoneRepository.FindByQueryable(x => x.DeleteFlag == false),
loginAndloginStatusAndloginHasRoleAndrole => loginAndloginStatusAndloginHasRoleAndrole.loginAndloginStatus.login.Id,
loginhasphone => loginhasphone.LoginId,
(loginAndloginStatusAndloginHasRoleAndrole, loginhasphone) => new { loginAndloginStatusAndloginHasRoleAndrole, loginhasphone })
.Select(x => new LoginUserDTO()
{
LoginFirstName = x.loginAndloginStatusAndloginHasRoleAndrole.loginAndloginStatus.login.LoginFirstName,
LoginLastName = x.loginAndloginStatusAndloginHasRoleAndrole.loginAndloginStatus.login.LoginLastName,
LoginEmail = x.loginAndloginStatusAndloginHasRoleAndrole.loginAndloginStatus.login.LoginEmail,
LoginStatusName = x.loginAndloginStatusAndloginHasRoleAndrole.loginAndloginStatus.loginStatus.LoginStatusName,
RoleName = x.loginAndloginStatusAndloginHasRoleAndrole.loginHasRole.Role.RoleName,
AllowSms = x.loginhasphone.Phone.AllowSms,
PhoneNumber = x.loginhasphone.Phone.PhoneNumber,
}).FirstOrDefault();
return result;
}
The method returns the users details using UserId , I was getting error when I was mocking the repositories using setup , was not able to join the repositories
using Capstone2.DTO.Models;
using Capstone2.Entities;
using Capstone2.Entities.Entities;
using Capstone2.Repository.Interfaces;
using Capstone2.Service.Services;
using Moq;
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
namespace Capstone2_API_Tests.Services
{
\[TestFixture\]
public class LoginServiceTest
{
protected Mock\<ILoginRepository\> \_mockLoginRepository;
protected Mock\<ILoginHasPhoneRepository\> \_mockLoginHasPhoneRepository;
protected Mock\<ILoginHasRoleRepository\> \_mockLoginHasRoleRepository;
protected Mock\<ILoginStatusRepository\> \_mockLoginStatusRepository;
protected Mock\<IPhoneRepository\> \_mockPhoneRepository;
protected Mock\<IRoleRepository\> \_mockRoleRepository;
protected Mock\<IPhoneTypeRepository\> \_mockPhoneTypeRepository;
protected LoginService \_loginService = null;
[SetUp]
public void Setup()
{
_mockLoginRepository = new Mock<ILoginRepository>();
_mockLoginHasPhoneRepository = new Mock<ILoginHasPhoneRepository>();
_mockLoginHasRoleRepository = new Mock<ILoginHasRoleRepository>();
_mockLoginStatusRepository = new Mock<ILoginStatusRepository>();
_mockPhoneRepository = new Mock<IPhoneRepository>();
_mockRoleRepository = new Mock<IRoleRepository>();
_mockPhoneTypeRepository = new Mock<IPhoneTypeRepository>();
_loginService = new LoginService(_mockLoginRepository.Object,
_mockLoginHasPhoneRepository.Object,
_mockLoginHasRoleRepository.Object,
_mockLoginStatusRepository.Object,
_mockPhoneRepository.Object,
_mockRoleRepository.Object,
_mockPhoneTypeRepository.Object);
_mockLoginRepository.Setup(m => m.FindByQueryable(x => x.DeleteFlag == false && x.Id == 1)).Returns(
new List<Login> { new Login()
{
Id = 1,
LoginFirstName = "Aman",
LoginLastName = "Singh",
LoginEmail = "amansingh71130#gmail.com",
Password = "9d6PamEkXI1eOjz6BTHMU8E4qmVwKk0yBwSI/AJzYws=",
LoginStatusId = 1,
FailedLoginAttempts = 4,
IsLocked = false,
RegistrationStatus = true,
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
} }.AsQueryable());
_mockLoginHasPhoneRepository.Setup(m => m.FindByQueryable(x => x.DeleteFlag == false)).Returns(
new List<LoginHasPhone> { new LoginHasPhone()
{
Id = 1,
LoginId = 1,
PhoneId = 1,
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
DeleteFlag = false,
}}.AsQueryable());
_mockLoginHasRoleRepository.Setup(m => m.FindByQueryable(x => x.DeleteFlag == false)).Returns(
new List<LoginHasRole> { new LoginHasRole()
{
Id = 1,
RoleId = 1,
LoginId = 1,
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
DeleteFlag = false,
} }.AsQueryable());
_mockLoginStatusRepository.Setup(m => m.FindByQueryable(x => x.DeleteFlag == false)).Returns(
new List<LoginStatus> { new LoginStatus()
{
Id = 1,
LoginStatusName = "Active",
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
DeleteFlag = false,
} }.AsQueryable());
_mockPhoneRepository.Setup(m => m.FindByQueryable(x => x.DeleteFlag == false)).Returns(
new List<Phone> { new Phone()
{
Id = 1,
PhoneNumber = "1234",
PhoneTypeId = 1,
AllowSms = true,
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
DeleteFlag = false,
}}.AsQueryable());
_mockRoleRepository.Setup(m => m.FindByQueryable(x => x.DeleteFlag == false)).Returns(
new List<Role> { new Role()
{ Id = 1,
RoleName ="Admin",
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
DeleteFlag = false,
}}.AsQueryable());
PhoneType phoneType = new PhoneType()
{ Id = 1,
PhoneTypeDesc = "12",
CreatedBy = 1,
CreatedDateTime = System.DateTime.UtcNow,
DeleteFlag = false,
};
_mockPhoneTypeRepository.Setup(x => x.GetById(1)).Returns(phoneType);
}
[TearDown]
public void Teardown()
{
}
[Test]
public void GetUserById_Successful()
{
//Act
int Id = 1;
var result = _loginService.GetUserDetailsById(Id);
//Assert
Assert.Pass();
}
}
}
tried this way, But I was getting Null in result.

Related

Cannot compose correct Linq query for a class having collection properties - getting EfCore5 translation errors

I have flat collection of the following data (IQueryable<Article>) which was obtained by querying DB:
ArticleId
LanguageName
ArticleText
ExtraData1
ExtraData2
1
English
EngText1
Something1
Something2
1
English
EngText2
Another1
Another2
1
French
FraText1
Blabla1
2
English
EngText2
Ololo1
Blabla2
2
German
GerText1
Naturlisch2
Now I need to fill the IQueryable<AgregatedArticle>: the idea is grouping by ArticleId and putting repeating data into nested list:
public class AgregatedArticle {
public int ArticleId { get; set; }
public List<Data> ArticleTexts { get; set; }
public class Data {
public string LanguageName { get; set; }
public string ArticleText { get; set; }
}
}
Unfortunately, I cannot make it: I am getting various EfCore5 translation errors and don't know: if it's me or EfCore5 bugs or limitations. I wasted 3 days trying different approaches. Please help - I was unable to find suitable examples in Internet. The problem comes up when I try to fill ArticleTexts property.
Here is the simplified example:
private async Task<IQueryable<LawArticleAggregated>> GetLawArticlesGroupedById(DbSet<LawArticleDetail> dbSet, string userContentLangRestriction = null)
{
var dbContext = await GetDbContextAsync();
var articlesQuery =
(from articleIds in dbSet.Select(x => x.ArticleId).Distinct()
from articlesPerId in dbSet
.Where(x => x.ArticleId == articleIds.ArticleId)
join askedL in dbContext.Langs
.Where(l => l.LanguageCode == userContentLangRestriction)
on
articlesPerId.LanguageCode
equals
askedL.StringValue
into askedLanguages
from askedLawLanguage in askedLanguages.DefaultIfEmpty()
join fallbackL in dbContext.Langs
.Where(l => l.LanguageCode == CoreConstants.LanguageCodes.English)
on
articlesPerId.LanguageCode
equals
fallbackL.StringValue
into fallbackLanguages
from fallbackLanguage in fallbackLanguages.DefaultIfEmpty()
select new
{
ArticleId = articleIds.ArticleId,
ArticleText = articlesPerId.ArticleText,
LanguageName = askedLawLanguage.ShortName ?? fallbackLanguage.ShortName
})
.OrderBy(x => x.ArticleId).ThenBy(x => x.LanguageName).ThenBy(x => x.ArticleText);
await articlesQuery.LoadAsync();
var aggregatedArticleData = articlesQuery.Select(x => new
{
ArticleId = x.ArticleId,
ArticleText = x.ArticleText,
LanguageName = x.LanguageName
});
var aggregatedArticles = articlesQuery.Select(x => x.ArticleId).Distinct().Select(x => new ArticleAggregated
{
ArticleId = x.ArticleId,
ArticleTexts = aggregatedArticleData.Where(a => a.ArticleId == x.ArticleId)
.Select(x => new LawArticleAggregated.Data
{
ArticleText = x.ArticleText,
LanguageName = x.LanguageName
}).ToList()
});
return aggregatedArticles;
}
For this specific code the exception is as follows:
Unable to translate collection subquery in projection since the parent
query doesn't project key columns of all of it's tables which are
required to generate results on client side. This can happen when
trying to correlate on keyless entity or when using 'Distinct' or
'GroupBy' operations without projecting all of the key columns.
I think I have reverse engineered your query. Big difference that we cannot return IQueryable from this funcrtio, but prepared IEnumerable. So if you have pagination later, better to pass page info into function parameters.
private async Task<IEnumerable<LawArticleAggregated>> GetLawArticlesGroupedById(DbSet<LawArticleDetail> dbSet, string userContentLangRestriction = null)
{
var dbContext = await GetDbContextAsync();
var articlesQuery =
from article in dbSet
from askedLawLanguage in dbContext.Langs
.Where(askedLawLanguage => askedLawLanguage.LanguageCode == userContentLangRestriction && article.LanguageCode == askedLawLanguage.StringValue)
.DefaultIfEmpty()
from fallbackLanguage in dbContext.Langs
.Where(fallbackLanguage => fallbackLanguage.LanguageCode == CoreConstants.LanguageCodes.English && article.LanguageCode == fallbackLanguage.StringValue)
.DefaultIfEmpty()
select new
{
ArticleId = article.ArticleId,
ArticleText = article.ArticleText,
LanguageName = askedLawLanguage.ShortName ?? fallbackLanguage.ShortName
};
articlesQuery = articlesQuery
.OrderBy(x => x.ArticleId)
.ThenBy(x => x.LanguageName)
.ThenBy(x => x.ArticleText);
var loaded = await articlesQuery.ToListAsync();
// group on the client side
var aggregatedArticles = loaded.GroupBy(x => x.ArticleId)
.Select(g => new ArticleAggregated
{
ArticleId = g.Key,
ArticleTexts = g.Select(x => new LawArticleAggregated.Data
{
ArticleText = x.ArticleText,
LanguageName = x.LanguageName
}).ToList()
});
return aggregatedArticles;
}
I ended up with the following implementation (I show it "as is", without simplification from the first message to demonstrate the approach, slightly modified from the initial variant to use proper paging):
private async Task<IEnumerable<LawArticleAggregated>> GetLawArticlesGroupedByIdListAsync(
DbSet<LawArticleDetail> dbSet,
Expression<Func<IQueryable<LawArticleDetail>, IQueryable<LawArticleDetail>>> filterFunc,
int skipCount,
int maxResultCount,
string userContentLangRestriction = null,
CancellationToken cancellationToken = default
)
{
var dbContext = await GetDbContextAsync();
var articlesQuery =
(from articleIds in filterFunc.Compile().Invoke(dbSet).Select(x => new { x.TenantId, x.LawArticleId })
.Distinct().OrderBy(x => x.TenantId).OrderByDescending(x => x.LawArticleId).Skip(skipCount).Take(maxResultCount)
from articlesPerId in dbSet
.Where(x => x.TenantId == articleIds.TenantId && x.LawArticleId == articleIds.LawArticleId)
join askedL in dbContext.FixCodeValues
.Where(l =>
l.DomainId == CoreConstants.Domains.CENTRAL_TOOLS
&& l.CodeName == CoreConstants.FieldTypes.LANGUAGE
&& l.LanguageCode == userContentLangRestriction)
on
articlesPerId.LanguageCode
equals
askedL.StringValue
into askedLanguages
from askedLawLanguage in askedLanguages.DefaultIfEmpty()
join fallbackL in dbContext.FixCodeValues
.Where(l =>
l.DomainId == CoreConstants.Domains.CENTRAL_TOOLS
&& l.CodeName == CoreConstants.FieldTypes.LANGUAGE
&& l.LanguageCode == CoreConstants.LanguageCodes.English)
on
articlesPerId.LanguageCode
equals
fallbackL.StringValue
into fallbackLanguages
from fallbackLanguage in fallbackLanguages.DefaultIfEmpty()
select new
{
TenantId = articleIds.TenantId,
LawArticleId = articleIds.LawArticleId,
Shortcut = articlesPerId.Shortcut,
ArticleText = articlesPerId.ArticleText,
LanguageName = askedLawLanguage.ShortName ?? fallbackLanguage.ShortName
})
.OrderBy(x => x.TenantId).ThenByDescending(x => x.LawArticleId).ThenBy(x => x.Shortcut).ThenBy(x => x.LanguageName).ThenBy(x => x.ArticleText);
var articleList = await articlesQuery.ToListAsync(cancellationToken);
var aggregatedArticles = articleList.GroupBy(x => new { x.TenantId, x.LawArticleId })
.Select(g => new LawArticleAggregated
{
TenantId = g.Key.TenantId,
LawArticleId = g.Key.LawArticleId,
ArticleTexts = g.Select(x => new LawArticleAggregated.Data
{
Shortcut = x.Shortcut,
ArticleText = x.ArticleText,
LanguageName = x.LanguageName
}).ToList()
});
return aggregatedArticles;
}
private async Task<long> GetLawArticlesGroupedByIdCountAsync(
DbSet<LawArticleDetail> dbSet,
Expression<Func<IQueryable<LawArticleDetail>, IQueryable<LawArticleDetail>>> filterFunc,
CancellationToken cancellationToken = default
)
{
return await filterFunc.Compile().Invoke(dbSet).GroupBy(x => new { x.TenantId, x.LawArticleId }).LongCountAsync(cancellationToken);
}

asp.net core3 error: not all code paths return a value

I have two tables with similar data for body insurance and third party car insurance ... I have used enum in the model to separate the insurances and I want to do the creation operation for it .... There are two modes for each insurance. One case when that car does not have insurance yet and the second case when we want to extend it.
I wrote this code to create the form, but it encounters the following error
I also get an error on the name of the Create function.error = not all code paths return a value.
Please advise
public async Task<IActionResult> Create(int id, int type)
{
InsuranceViewModel model;
ViewBag.Type = type;
var companies = await _context.InsuranceCompany
.Where(e => e.IsActice)
.ToListAsync();
ViewData["CompanyList"] = new SelectList(companies, "Id", "CompanyName");
if ((InsuranceType)type == InsuranceType.Body)
{
var bodyInsurance = await _context.BodyInsurance
.Include(e => e.InsuranceCompany)
.FirstOrDefaultAsync(e => e.Id == id);
if (bodyInsurance == null)
{
model = new InsuranceViewModel
{
CompanyId = bodyInsurance.InsuranceCompanyId,
CompanyName = bodyInsurance.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(bodyInsurance.IssueDate).Ticks,
ExpireDate = new DateTime(bodyInsurance.ExpireDate).Ticks,
VehicleInformationId = id
};
}
else
{
var lastBody = await _context.BodyInsurance.Include(e => e.InsuranceCompany)
.Where(e => e.VehicleInformationId == id)
.OrderBy(e => e.ExpireDate)
.LastAsync();
model = new InsuranceViewModel
{
ExpireDate = new DateTime(lastBody.ExpireDate).AddYears(1).AddDays(1).Ticks,
CompanyId = lastBody.InsuranceCompanyId,
CompanyName = lastBody.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(lastBody.ExpireDate).AddDays(1).Ticks,
VehicleInformationId = id
};
}
}
else
{
if ((InsuranceType)type == InsuranceType.Thirdpart)
{
var thirdParty = await _context.ThirdPartyInsurance
.Include(e => e.InsuranceCompany)
.FirstOrDefaultAsync(e => e.Id == id);
if (thirdParty == null)
{
model = new InsuranceViewModel
{
CompanyId = thirdParty.InsuranceCompanyId,
CompanyName = thirdParty.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(thirdParty.IssueDate).Ticks,
ExpireDate = new DateTime(thirdParty.ExpireDate).Ticks,
VehicleInformationId = id
};
}
else
{
var lastThirdParty = await _context.ThirdPartyInsurance.Include(e => e.InsuranceCompany)
.Where(e => e.VehicleInformationId == id)
.OrderBy(e => e.ExpireDate)
.LastAsync();
model = new InsuranceViewModel
{
ExpireDate = new DateTime(lastThirdParty.ExpireDate).AddYears(1).AddDays(1).Ticks,
CompanyId = lastThirdParty.InsuranceCompanyId,
CompanyName = lastThirdParty.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(lastThirdParty.ExpireDate).AddDays(1).Ticks,
VehicleInformationId = id
};
}
}
return View(model);
}

Dynamic where clause with two entity

I need a filter between two entity.
Have two tables 1.User 2.Product
Product map with the User table.
I am going to create a dynamic where filter.
I need to find out all the users which have 'test' product.
Conditions: if userFilter count is 0 then I need all test product with the respected user.
If userFilter is there and productFilter is there then below code is working but if userFilter is not there and productFilter is there then it returning 0 row. How can I find the users which have test product? ?
Here is my Code.
public IHttpActionResult GetFilter()
{
var userFilters = new List<Filter>()
{
new Filter { PropertyName = "Username" ,
Operation = Op .Equals, Value = "Karan" },
};
var productfilter = new List<Filter>()
{
new Filter { PropertyName = "Name" ,
Operation = Op .Equals, Value = "Test product" }
};
Func<User, bool> deleg = x => true;
Func<Product, bool> delegProduct = x => true;
if (userFilters.Count > 0)
{
deleg = ExpressionBuilder.GetExpression<User>(userFilters).Compile();
}
if (productfilter.Count > 0)
{
delegProduct = ExpressionBuilder.GetExpression<Product>(productfilter).Compile();
}
var resultt = _localmarketEntities.Users.Where(deleg)
.Select(x => new
{
x.Id,
x.Username,
Product = x.Products.Where(delegProduct).Select(y => new
{
y.Id,
y.Name
}).ToList()
})
.ToList();
return Ok(resultt);
}
if i understand correct, you need all users that have test product when userFiler count is 0.
List<User> res;
var user = _localmarketEntities.Users.Where(deleg).ToList();
if (user.Count == 0) {
res = _localmarketEntities.Products.Where(delegProduct).Select(q => new User() {
Id = q.Id,
Username = q.Username,
Product = q
}).ToList();
}
else {
res = _localmarketEntities.Users.Where(deleg)
.Select(x => new
{
x.Id,
x.Username,
Product = x.Products.Where(delegProduct).Select(y => new
{
y.Id,
y.Name
}).ToList()
})
.ToList();
}

join 4 tables with linq

I'm trying to join 4 tables using linq.
This is my code,
var query = Context.AanvraagV.Join(Context.IdnPartijMVSet, aanvraag => aanvraag.AlvNummer, partijMv => partijMv.AlvNummer, (aanvraag, partijMv) => new { aanvraag, partijMv })
.Join(Context.DossierVaststellingSet, aanvraag => aanvraag.aanvraag.AanvraagId, dossierVaststelling => dossierVaststelling.DossierVersieId, (aanvraag, dossierVaststelling) => new { aanvraag, dossierVaststelling })
.Join(Context.IdnPartijVoorkeurContactMVSet, aanvraag => aanvraag.aanvraag.partijMv.AlvNummer, partijVoorkeur => partijVoorkeur.AlvNummer, (aanvraag, partijVoorkeur) => new { aanvraag, partijVoorkeur });
Then I return a query and this is what I get
return query.Select(x => new ZoekResultaatDto{
AanvraagNummer = x.aanvraag.aanvraag.aanvraag.DossierNummer,
Versie = x.aanvraag.aanvraag.aanvraag.AanvraagVersie,
StartjaarAanvraag = x.aanvraag.aanvraag.aanvraag.AanvraagStartCampagne,
EindjaarAanvraag = x.aanvraag.aanvraag.aanvraag.AanvraagEindCampagne,
Maatregel = x.aanvraag.aanvraag.aanvraag.Maatregel,
Pakket = x.aanvraag.aanvraag.aanvraag.MaatregelPakket,
AanvraagType = x.aanvraag.aanvraag.aanvraag.Aanvragtype,
Eenheid = x.aanvraag.aanvraag.aanvraag.VerbintenisWaardeEenheid,
VerbintenisOppervlakte = x.aanvraag.aanvraag.aanvraag.VerbintenisWaarde,
KeuzeBevestiging = x.aanvraag.aanvraag.aanvraag.KeuzeBevestiging,
IndieningsdatumAanvraag = x.aanvraag.aanvraag.aanvraag.AanvraagIndieningsDatum,
Status = x.aanvraag.aanvraag.aanvraag.AanvraagStatus,
LandbouwerNummer = x.aanvraag.aanvraag.aanvraag.AlvNummer,
Naam = x.aanvraag.aanvraag.partijMv.Naam,
Rechtsvorm = x.aanvraag.aanvraag.partijMv.Rechtsvorm ,
Adres = string.Format("{0} {1} {2}", x.aanvraag.aanvraag.partijMv.Straat, x.aanvraag.aanvraag.partijMv.Huisnummer, x.aanvraag.aanvraag.partijMv.Bus),
Postcode = x.aanvraag.aanvraag.partijMv.Postcode,
Gemeente = x.aanvraag.aanvraag.partijMv.Gemeente,
EmailaAdres = x.partijVoorkeur.Email,
OpmerkingCode = x.aanvraag.dossierVaststelling.VaststellingCode,
OpmerkingOmschrijving = RefVaststellingResources.OMSCHRIJVING(x.aanvraag.dossierVaststelling)
}).ToList();
But this is not what I want. What i want is this. How can I change the joins to get this instead?
return query.Select(x => new ZoekResultaatDto{
AanvraagNummer = x.aanvraag.DossierNummer,
Versie = x.aanvraag.AanvraagVersie,
StartjaarAanvraag = x.aanvraag.AanvraagStartCampagne,
EindjaarAanvraag = x.aanvraag.AanvraagEindCampagne,
Maatregel = x.aanvraag.Maatregel,
Pakket = x.aanvraag.MaatregelPakket,
AanvraagType = x.aanvraag.Aanvragtype,
Eenheid = x.aanvraag.VerbintenisWaardeEenheid,
VerbintenisOppervlakte = x.aanvraag.VerbintenisWaarde,
KeuzeBevestiging = x.aanvraag.KeuzeBevestiging,
IndieningsdatumAanvraag = x.aanvraag.AanvraagIndieningsDatum,
Status = x.aanvraag.AanvraagStatus,
LandbouwerNummer = x.aanvraag.AlvNummer,
Naam = x.partijMv.Naam,
Rechtsvorm = x.partijMv.Rechtsvorm ,
Adres = string.Format("{0} {1} {2}", x.partijMv.Straat, x.partijMv.Huisnummer, x.partijMv.Bus),
Postcode = x.partijMv.Postcode,
Gemeente = x.partijMv.Gemeente,
EmailaAdres = x.partijVoorkeur.Email,
OpmerkingCode = x.dossierVaststelling.VaststellingCode,
OpmerkingOmschrijving = RefVaststellingResources.OMSCHRIJVING(x.dossierVaststelling)
}).ToList();
I did it. And also solved the problem of returning a AnonymousType
public class ZoekResultaatLijstDto
{
public AanvraagV aanvraag { get; set; }
public IdnPartijMV idnPartijMv { get; set; }
public DossierVaststelling dossierVast { get; set; }
public IdnPartijVoorkeurContactMV idnPartijVoor { get; set; }
}
public List<ZoekResultaatLijstDto> GetItems(ZoekCriteriaDto zoekCriteria)
{
IQueryable<ZoekResultaatLijstDto> query = Context.AanvraagV.Join(Context.IdnPartijMVSet, aanvraag => aanvraag.AlvNummer, partijMv => partijMv.AlvNummer, (aanvraag, partijMv) => new { aanvraag, partijMv })
.Join(Context.DossierVaststellingSet, aanvraag => aanvraag.aanvraag.AanvraagId, dossierVaststelling => dossierVaststelling.DossierVersieId,
(aanvraag, dossierVaststelling) => new { aanvraag, dossierVaststelling }).Select( j => new {j.aanvraag, j.aanvraag.partijMv, j.dossierVaststelling})
.Join(Context.IdnPartijVoorkeurContactMVSet, aanvraag => aanvraag.aanvraag.partijMv.AlvNummer, partijVoorkeur => partijVoorkeur.AlvNummer, (aanvraag, partijVoorkeur) => new { aanvraag, partijVoorkeur })
.Select(m => new ZoekResultaatLijstDto() { aanvraag = m.aanvraag.aanvraag.aanvraag, dossierVast = m.aanvraag.dossierVaststelling, idnPartijMv = m.aanvraag.partijMv, idnPartijVoor = m.partijVoorkeur });
return query.Select(zoekResultaat => zoekResultaat).ToList();
}

Convert Lambda Expression into an Expression tree

I have that lambda:
var Ids = profileExample.CostCenters
.Where(CostCentre => CostCentre != null)
.Select(CostCentre => CostCentre.Id);
Then i convert to that expression tree
static IEnumerable<Int64> AboveLambdaConvertedToExpressionTree(Profile profileExample)
{
//Begin var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
var property = profileExample.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != "Id").First();
var collection = ((IEnumerable)property.GetValue(profileExample, null)).AsQueryable();
var collectionType = property.PropertyType.GetGenericArguments()[0];
var collectionTypeName = collectionType.Name;
var keyType = typeof(Int64);
var keyName = "Id";
//BeginWhere
var parameter = Expression.Parameter(collectionType, collectionTypeName);
var profileExampleWhere = Expression.Lambda(
Expression.NotEqual(parameter, Expression.Constant(null)),
parameter);
var profileExampleWhereCall = Expression.Call(typeof(Enumerable),
"Where",
new Type[] { collectionType },
collection.Expression,
profileExampleWhere);
//EndWhere
//BeginSelect
var profileExampleSelect = Expression.Lambda(Expression.PropertyOrField(parameter, keyName),
parameter);
var profileExampleSelectCall = Expression.Call(typeof(Enumerable),
"Select",
new Type[] { collectionType, keyType },
profileExampleWhereCall,
profileExampleSelect);
var Ids = Expression.Lambda(profileExampleSelectCall).Compile().DynamicInvoke();
//EndSelect
//End var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
return ((IEnumerable)Ids).Cast<Int64>();
}
Now i want to do the same with bellow lambda
var result = Set.AsQueryable()
.Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id)
.Any(Id => Ids.Contains(Id))).ToList();
But i stuck in .Any(Id => Ids.Contains(Id))....
var id = Expression.Parameter(typeof(long), "Id");
var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
var profile = Expression.Parameter(typeof(Profile), "Profile");
var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
var selectCall = Expression.Call(typeof(Enumerable),
"Select",
new Type[] { typeof(CostCentre), typeof(long) },
Expression.PropertyOrField(profile, "CostCenters"),
selectLambda);
How can i call Any from selectCall and call Ids.Contains...
Full code to run as console application bellow:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressionTrees
{
class Program
{
static void Main(string[] args)
{
var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
Ids = AboveLambdaConvertedToExpressionTree(profileExample);
var result = Set.AsQueryable().Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();
//Expression<Func<Profile, bool>> lambda = (Profile) => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id));
var id = Expression.Parameter(typeof(long), "Id");
var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
var profile = Expression.Parameter(typeof(Profile), "Profile");
var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
var selectCall = Expression.Call(typeof(Enumerable),
"Select",
new Type[] { typeof(CostCentre), typeof(long) },
Expression.PropertyOrField(profile, "CostCenters"),
selectLambda);
}
static IEnumerable<Int64> AboveLambdaConvertedToExpressionTree(Profile profileExample)
{
// I show that as example of what i need to do
var keyType = typeof(Int64);
var keyName = "Id";
//Begin var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
var property = profileExample.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != keyName).First();
var collection = ((IEnumerable)property.GetValue(profileExample, null)).AsQueryable();
var collectionType = property.PropertyType.GetGenericArguments()[0];
var collectionTypeName = collectionType.Name;
//BeginWhere
var parameter = Expression.Parameter(collectionType, collectionTypeName);
var profileExampleWhere = Expression.Lambda(
Expression.NotEqual(parameter, Expression.Constant(null)),
parameter);
var profileExampleWhereCall = Expression.Call(typeof(Enumerable),
"Where",
new Type[] { collectionType },
collection.Expression,
profileExampleWhere);
//EndWhere
//BeginSelect
var profileExampleSelect = Expression.Lambda(Expression.PropertyOrField(parameter, keyName),
parameter);
var profileExampleSelectCall = Expression.Call(typeof(Enumerable),
"Select",
new Type[] { collectionType, keyType },
profileExampleWhereCall,
profileExampleSelect);
var Ids = Expression.Lambda(profileExampleSelectCall).Compile().DynamicInvoke();
//EndSelect
//End var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
return ((IEnumerable)Ids).Cast<Int64>();
}
public partial class Profile
{
public virtual Int64 Id { get; set; }
public virtual ICollection<CostCentre> CostCenters { get; set; }
}
public partial class CostCentre
{
public virtual Int64 Id { get; set; }
}
public static Profile profileExample
{
get
{
return new Profile()
{
Id = 1,
CostCenters = new List<CostCentre>() { new CostCentre() { Id = 2 } }
};
}
}
public static IList<Profile> Set
{
get
{
return new List<Profile>() { new Profile() { Id = 1,
CostCenters = new List<CostCentre>() { new CostCentre() { Id = 1 },
new CostCentre() { Id = 2 } }
},
new Profile() { Id = 2,
CostCenters = new List<CostCentre>() { new CostCentre() { Id = 2 },
new CostCentre() { Id = 3 } }
},
new Profile() { Id = 3,
CostCenters = new List<CostCentre>() { new CostCentre() { Id = 3 } }
} };
}
}
}
}
Since Any is a Generic Method you need to create it for a specific type. The method below gets the Any<T> method from the Enumerable type.
public static MethodInfo GetAnyExtensionMethod(Type forType)
{
MethodInfo method =
typeof(Enumerable).GetMethods()
.First(m => m.Name.Equals("Any") &&
m.GetParameters().Count() == 2);
return method.MakeGenericMethod(new[] { forType });
}
Its solved with help of Mads from MS
class Program
{
static void Main(string[] args)
{
//var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
var Ids = AboveLambdaConvertedToExpressionTree(profileExample);
//var result = Set.AsQueryable().Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();
var id = Expression.Parameter(typeof(long), "Id");
var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
var profile = Expression.Parameter(typeof(Profile), "Profile");
var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
var selectCall = Expression.Call(typeof(Enumerable),
"Select",
new Type[] { typeof(CostCentre), typeof(long) },
Expression.PropertyOrField(profile, "CostCenters"),
selectLambda);
//var id2 = Expression.Parameter(typeof(long), "Id");
var containsCall = Expression.Call(typeof(Enumerable),
"Contains",
new Type[] { typeof(long) },
Expression.Constant(Ids),
id);
var anyLambda = Expression.Lambda(containsCall, id);
var anyCall = Expression.Call(typeof(Enumerable),
"Any",
new Type[] { typeof(long) },
selectCall,
anyLambda);
var whereLambda = Expression.Lambda(anyCall, profile);
var callExpression = Expression.Call(typeof(Queryable),
"Where",
new Type[] { typeof(Profile) },
Set.AsQueryable().Expression,
whereLambda);
var result = Expression.Lambda(callExpression).Compile().DynamicInvoke();
}

Resources