How to use NHibernate's ICriteria for grouping, fetching associations and T-SQL functions - tsql

I want to create the following T-SQL statement:
SELECT SUM (sa.Amount) as 'SumAmount',
SUM(sa.Cost) as 'SumCost',
gg.[Description] as 'Goodsgroup', Month(sa.[Date]) as 'Month'
FROM SalesmanArticle sa
INNER JOIN Article a
ON a.ArticleId = sa.ArticleId
INNER JOIN GoodsGroup gg
ON gg.GoodsGroupId = a.GoodsGroupId
GROUP BY gg.[Description], Month(sa.[Date])
ORDER BY 'Month', 'Goodsgroup'
Is this possible with NHibernates ICriteria?
How can I use the Month-T-SQL-Function?
Do I have to join manually or does the ICriteria API knows that when I use the propetyName 'SalesmanArticle.Article.Goodsgroup.Description' it has to join the Article and the Goodsgroup?
EDIT:
For now I have written this code here:
// typesafe properties
string article = typeof(Article).Name;
string goodsGroup = typeof(GoodsGroup).Name;
string salesmanArticle = typeof(SalesmanArticle).Name;
string amount = Reflector.GetPropertyName<SalesmanArticle>(x => x.Amount);
string cost = Reflector.GetPropertyName<SalesmanArticle>(x => x.Cost);
string description = string.Format("{0}.{1}",
goodsGroup, Reflector.GetPropertyName<SalesmanArticle>(x => x.Article.GoodsGroup.Description));
string date = Reflector.GetPropertyName<SalesmanArticle>(x => x.Date);
string formatedDate = string.Format("MONTH([{0}])", date);
return GetSession()
// FROM
.CreateCriteria(typeof(SalesmanArticle), salesmanArticle)
// JOIN
.CreateCriteria(article, article, JoinType.InnerJoin)
.CreateCriteria(goodsGroup, goodsGroup, JoinType.InnerJoin)
// SELECT
.SetProjection(Projections.ProjectionList()
.Add(Projections.Sum(amount))
.Add(Projections.Sum(cost))
// GROUP BY
.Add(Projections.GroupProperty(description))
.Add(Projections.SqlGroupProjection(formatedDate, formatedDate, new[]{"MyDate"} , new[] { NHibernateUtil.Int32 })))
.List();
But an AdoException is thrown:
could not execute query [ SELECT
sum(this_.Amount) as y0_,
sum(this_.Cost) as y1_,
goodsgroup2_.Description as y2_,
MONTH([Date]) FROM [SalesmanArticle]
this_ inner join [Article] article1_
on this_.ArticleId=article1_.ArticleId
inner join [GoodsGroup] goodsgroup2_
on
article1_.GoodsGroupId=goodsgroup2_.GoodsGroupId
GROUP BY goodsgroup2_.Description,
MONTH([Date]) ]
[SQL: SELECT
sum(this_.Amount) as y0_,
sum(this_.Cost) as y1_,
goodsgroup2_.Description as y2_,
MONTH([Date]) FROM [SalesmanArticle]
this_ inner join [Article] article1_
on this_.ArticleId=article1_.ArticleId
inner join [GoodsGroup] goodsgroup2_
on
article1_.GoodsGroupId=goodsgroup2_.GoodsGroupId
GROUP BY goodsgroup2_.Description,
MONTH([Date])]
The strange thing is that NHibernate tries to create 2 queries?!
AND BOTH of them are correct!
Instead of the codeline
.Add(Projections.SqlGroupProjection(formatedDate, formatedDate, new[]{"MyDate"} , new[] { NHibernateUtil.Int32 })))
I used
.Add(Projections.SqlFunction("MONTH", NHibernateUtil.Int32, Projections.GroupProperty(date))))
The problem with the SqlFunction is that it creates a GROUP BY sa.Date instead of MONTH(sa.Date). But this method worked syntactically correct.
So I switched to the SqlGroupProjection method.
But anyway it does not work.
Can anybody help me?

I solved it. Here is the correct code:
public class SalesmanArticleRepository : Repository<SalesmanArticle>, ISalesmanArticleRepository
{
public IList GetAllAll()
{
// typesafe properties
string article = typeof(Article).Name;
string goodsGroup = typeof(GoodsGroup).Name;
string salesmanArticle = typeof(SalesmanArticle).Name;
string amount = Reflector.GetPropertyName<SalesmanArticle>(x => x.Amount);
string cost = Reflector.GetPropertyName<SalesmanArticle>(x => x.Cost);
string description = string.Format("{0}.{1}",
goodsGroup, Reflector.GetPropertyName<SalesmanArticle>(x => x.Article.GoodsGroup.Description));
string date = Reflector.GetPropertyName<SalesmanArticle>(x => x.Date);
string formatedDateSql = string.Format("month({{alias}}.[{0}]) as mydate", date);
string formatedDateGroupBy = string.Format("month({{alias}}.[{0}])", date);
return GetSession()
// FROM
.CreateCriteria(typeof(SalesmanArticle), salesmanArticle)
// JOIN
.CreateCriteria(article, article, JoinType.InnerJoin)
.CreateCriteria(goodsGroup, goodsGroup, JoinType.InnerJoin)
// SELECT
.SetProjection(Projections.ProjectionList()
.Add(Projections.Sum(amount))
.Add(Projections.Sum(cost))
// GROUP BY
.Add(Projections.GroupProperty(description))
.Add(Projections.SqlGroupProjection(formatedDateSql, formatedDateGroupBy, new[] { "mydate" }, new[] { NHibernateUtil.Int32 })))
.List();
}
}

Related

How to pass a HashMap to CriteriaBuilder and add to Predicates list

I am currently receiving a Map<String, String> in the API request body. I have an entity,
class TagEntity {
#Column(name = "name", length = 128, nullable = false)
private String name;
#Column(name = "value", length = 256, nullable = false)
private String value;
}
There is a MachineEntity which has a Set<TagEntity>. It's a #OneToMany mapping. I am trying to fetch the machine entities according to the name and value passed in the HashMap (in request) which correspond to the TagEntity.
I tried this code below. However, it works only if I pass one name-value pair in the request. Suppose, if the HashMap contains 2 elements, the query returns an empty list when it should return 2 Machine Entities.
SetJoin<MachineEntity, TagEntity> join = root.join(MachineEntity_.tagEntities);
for (Map.Entry element : request.getTags().entrySet()) {
predicates.add(criteriaBuilder.and(
criteriaBuilder.equal(join.get(TagEntity_.name), element.getKey()),
criteriaBuilder.equal(join.get(TagEntity_.value), element.getValue())
));
}
Is there a way I can set the HashMap in CriteriaBuilder without iterating through the Map? I am clueless what can be done to solve this problem. Will greatly appreciate some help.
As always, writing the statement in (roughly) SQL helps:
SELECT ...
FROM Machine m
WHERE -- repeat for each map entry
EXISTS (SELECT ... FROM Tag t WHERE t.machine_id = m.id AND t.name = ?1 AND t.value = ?2)
AND EXISTS (SELECT ... FROM Tag t WHERE t.machine_id = m.id AND t.name = ?3 AND t.value = ?4)
...
If this suits your needs, it can be translated to criteria API roughly as follows (you will probably need to tweak it):
private Subquery<TagEntity> makeExistsSubquery(CriteriaQuery<MachineEntity> q, CriteriaBuilder cb, Map.Entry<String,String> e) {
Subquery<TagEntity> subquery = q.subquery(TagEntity.class);
Root<TagEntity> tagRoot = subquery.from(TagEntity.class);
subquery.where(cb.and(
cb.equal(tagRoot.get(TagEntity_.name), e.getKey()),
cb.equal(tagRoot.get(TagEntity_.value), e.getValue())
));
return subquery;
}
private void your_method() {
// assuming something like this exists:
CriteriaQuery<MachineEntity> query = criteriaBuilder.createQuery(MachineEntity.class);
// do this:
for (Map.Entry element : request.getTags().entrySet()) {
predicates.add(criteriaBuilder.exists(makeExistsSubquery(query, criteriaBuilder, element)));
}
...
}
I am not sure how efficient is this query going to be. But I hope this hints to a solution.
Additionally I am assuming you want machines that match ALL the given tags. If you want machines matching ANY of the given tags, the SQL query would be simpler:
SELECT ...
FROM Machine m JOIN Tag t ON t.machine_id = m.id
WHERE -- repeat for each map entry
t.name = ?1 AND t.value = ?2
OR t.name = ?3 AND t.value = ?4
...
Predicate tagsPredicate = criteriaBuilder.or(
request.getTags().entrySet().stream()
.map(e -> criteriaBuilder.and(
criteriaBuilder.equal(join.get(TagEntity_.name), e.getKey()),
criteriaBuilder.equal(join.get(TagEntity_.value), e.getValue())
))
.collect(Collectors.toList())
.toArray(new Predicate[0])
);
// add the tagsPredicate to your where clause, if the user has actually defined tag criteria

Nested Query Entity Framework

Need help in converting below SQL nested query to a LINQ query?
select P.ProductId, P.Name, C.Name, I.Image
from Product P
join ProductImage I on P.ProductId = I.ProductId
join ProductCategory C on P.Category = C.CategoryId
where P.ProductId in (select distinct ProductId
from ProductVariantMapping M
where M.GUID in (select top 3 V.Guid
from [Order] O
join Inventory V on V.InventoryId = O.InventoryId
group by O.InventoryId, V.Guid
order by Sum(O.Quantity) desc))
Below is my attempt in converting to LINQ query :
var a = (from product in ekartEntities.Products
join productImage in ekartEntities.ProductImages
on product.ProductId equals productImage.ProductId
join category in ekartEntities.ProductCategories
on product.Category equals category.CategoryId
where product.ProductId
select new ProductDTO()
{
ProductId = product.ProductId,
Name = product.Name,
Category = category.Name,
Image = productImage.Image
}).ToList();
what is the equivalent of "IN" when converting to LINQ .
I got the solution for 'IN' clause.
But how do I use sum(Quantity) in order by after grouping?
I am new to Entity Framework. Can anyone help me?
In LINQ, you will need to use the "contains()" method to generate the 'IN' You need to put a list in the Contains method. If sends a query, that query will be repeated for completions and this will lead to performance loss.
Sample:
var sampleList = (from order ekartEntities.Order
join inventory in ekartEntities.Inventory on order.InventoryId equals inventory.InventoryId
select order).toList();
var query = (from product in ekartEntities.Products
join productImage in ekartEntities.ProductImages
on product.ProductId equals productImage.ProductId
join category in ekartEntities.ProductCategories
on product.Category equals category.CategoryId
where sampleList.Contains(product.ProductId)
select new ProductDTO()
{
ProductId = product.ProductId,
Name = product.Name,
Category = category.Name,
Image = productImage.Image
}).ToList();
Do not apply ToList() in the first query
I made some test.
Test 1 (with my own data):
var phIds = new List<string>
{
//List of Ids
};
using (var db = new ApplicationDbContext())
{
var studentsId = db.Relations
.Where(x => phIds.Contains(x.RelationId))
.Select(x => x.Id)
.Distinct(); //IQueryable here
var studentsQuery = from p in db.Students
where studentsId.Contains(p.Id)
select p;
var students= studentsQuery .ToList();
}
The generated query looks like :
SELECT
[Extent1].[Id] AS [Id],
[...]
FROM [dbo].[Students] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM ( SELECT DISTINCT
[Extent2].[StudentId] AS [StudentId]
FROM [dbo].[Relations] AS [Extent2]
WHERE ([Extent2].[RelationId] IN (N'ccd31c3d-dfa3-4b40-...', N'd2cb05a2-ece3-4060-...'))
) AS [Distinct1]
WHERE [Distinct1].[StudentId] = [Extent1].[Id]
)
The query looks exactly like I wanted
However, if you add the ToList() in the first query to get the ids, you no longer have an IQueryable but a list.
Test 2 : wrong (I added ToList):
var phIds = new List<string>
{
//List of Ids
};
using (var db = new ApplicationDbContext())
{
var studentsId = db.Relations
.Where(x => phIds.Contains(x.RelationId))
.Select(x => x.Id)
.Distinct().ToList(); // No longer IQueryable but a list of 3000 int
var studentsQuery = from p in db.Students
where studentsId .Contains(p.Id)
select p;
var students= studentsQuery .ToList();
}
The generated query is ugly:
SELECT
[Extent1].[Id] AS [Id],
[...]
FROM [dbo].[Patients] AS [Extent1]
WHERE [Extent1].[Id] IN (611661, 611662, 611663, 611664,....
//more than 3000 ids here
)

Can't add/sum string values in IEnumerable

The ultimate goal is to display a GrandTotal column using Highcharts. The GrandTotal should be the sum of TotalAmount for a given Offer id. TotalAmount is a string and the values are like $10.00 or 10.00. GrandTotal is an int, but could easily be changed. Here is what I have done so far.
Step 1) Convert the two IEnumerable lists into their ViewModel counterparts. I set GrandTotal to 0 here because I don't know the amount.
var offersConvert = offers
.Select(o => new OfferSummaryViewModel
{
Id = o.Id,
Name = o.Name,
Created = o.Created,
Shares = o.Shares,
Redemptions = o.Redemptions,
GrandTotal = 0
})
.ToList();
var sharedOffersConvert = sharedOffers
.Select(s => new SharedOfferViewModel
{
OfferId = s.OfferId,
//TotalAmount = s.TotalAmount.Replace("$", string.Empty).Replace(",", string.Empty).Trim()
TotalAmount = s.TotalAmount
})
//.Where(i => i.TotalAmount != null)
.ToList();
Step 2) Join the two lists on the Id of the Offer.
var data = offersConvert
.Join(sharedOffersConvert,
o => o.Id,
s => s.OfferId,
(o, s) => new { offersConvert = o, sharedOffersConvert = s })
.Select(o => new
{
Id = o.offersConvert.Id,
Created = o.offersConvert.Created,
Shares = o.offersConvert.Shares,
Redemptions = o.offersConvert.Redemptions,
Name = o.offersConvert.Name,
OfferId = o.sharedOffersConvert.OfferId,
TotalAmount = o.sharedOffersConvert.TotalAmount,
//GrandTotal = Convert.ToInt32(o.sharedOffersConvert.TotalAmount.Replace("$", string.Empty).Replace(",", string.Empty).Trim())
//GrandTotal = Convert.ToInt32(Convert.ToDouble(o.sharedOffersConvert.TotalAmount, CultureInfo.InvariantCulture))
})
//.Where(o => o.Id == o.OfferId)
.OrderBy(o => o.Created.Add(offset))
.ToList();
As you can tell, I've tried to remove any dollar signs and commas. I've even tried to trim white space in order to get clean data. I am then trying to convert the strings to int values, so I can sum them. Nothing seems to work. I've even tried .GroupBy and other methods (see below). At least with .GroupBy I can get to the .Sum operator. With the other method I run into issues when I can't convert int into ToList(), so I have to try and convert ToString().
.Where(o => o.Id == o.OfferId)
.GroupBy(g => g.Id)
.Select(x => new { GrandTotal = x.Sum(o => o.TotalAmount) })
ERROR in above: can't convert TotalAmount to decimal
.Where(i => i.Id == i.OfferId)
.Sum(i => Convert.ToInt32(Convert.ToDouble(i.TotalAmount, CultureInfo.InvariantCulture)
)).ToString()
Does anyone know how I can add/sum the string values in TotalAmount to get a GrandTotal per Offer id?
Any help us much appreciated. Thanks!
UPDATE: This works, but I really don't understand why and I don't think it is very clean. I really couldn't find many examples where people were joining two lists together and summing one of the columns. This seems pretty common to me, but perhaps it is not.
var data = (from o in offersConvert
join s in sharedOffersConvert on o.Id equals s.OfferId
orderby o.Created.Add(offset)
let k = new
{
Id = o.Id,
Name = o.Name,
Created = o.Created,
Shares = o.Shares,
Redemptions = o.Redemptions
}
group s by k into totals
select new
{
OfferId = totals.Key.Id,
Name = totals.Key.Name,
Created = totals.Key.Created,
Shares = totals.Key.Shares,
Id = totals.Key.Id,
Redemptions = totals.Key.Redemptions,
GrandTotal = totals.Sum((s => s.TotalAmount == null ? Decimal.Zero : Decimal.Parse(s.TotalAmount, NumberStyles.Currency)))
})
.ToList();
You can use
Decimal.TryParse("$10.00", NumberStyles.Currency, CultureInfo.CurrentCulture, out var res);
Or in the context of your LINQ,
GrandTotal = Decimal.Parse(o.sharedOffersConvert.TotalAmount, NumberStyles.Currency)
if o.sahredOffersConvert.TotalAmount may be null,
GrandTotal = (o.sharedOffersConvert.TotalAmount ==null) ? Decimal.Zero : Decimal.Parse(o.sharedOffersConvert.TotalAmount, NumberStyles.Currency)
I'm still puzzled why everyone lately has this odd fascination with the Lambda syntax. And that seems to have been only one of several means you've used to make this more complicated than necessary:
var data = (from o in offers
join s in sharedOffers on o.Id equals s.OfferId
orderby o.Created.Add(offset)
select new
{
Id = o.Id,
Created = o.Created,
Shares = o.Shares,
Redemptions = o.Redemptions,
Name = o.Name,
OfferId = o.OfferId,
TotalAmount = Decimal.Parse(o.TotalAmount, NumberStyles.Currency)
})
.ToList();
Further, as offset seems to be a constant (for the life of this query), adding it to Created isn't going to affect the ordering, and that bit can be removed.
And, since it appears your final output is just the grand totals, it can be reduced further to:
var data = (from o in offers
join s in sharedOffers on o.Id equals s.OfferId
orderby o.Created
group Decimal.Parse(o.TotalAmount, NumberStyles.Currency) by o.id into totals
select new
{
Id = totals.Key,
GrandAmount = totals.Sum()
})
.ToList();
UPDATE: Putting back what I took out... This should work (I don't have your tables, so I can't test it)
var data = (from o in offers
join s in sharedOffers on o.Id equals s.OfferId
orderby o.Created.Add
group o by o.Id into totals
let item = totals.First()
select new
{
Id = item.Id,
Created = item.Created,
Shares = item.Shares,
Redemptions = o.Redemptions,
Name = item.Name,
OfferId = item.OfferId,
GrandTotal = totals.Sum(t=>Decimal.Parse(t.TotalAmount, NumberStyles.Currency))
})
.ToList();

Left join after a into group in Linq using entity framework (core)

Problem: I would like to generate the exact sql below in the desired output using linq syntax (Entity framework 7)
The goal of the question is to generate the exact sql below!
Desired Output
select a.AppUserId, u.Email, a.FirstName, a.MiddleName, a.LastName, a.IsInternal, a.AspNetUserId, a.PictureLink, a.SignatureLink, a.PhoneNumber, a.Extension, a.FaxNumber, a.MobileNumber, a.Skype, r.Name as 'Role', a.SupervisorId, a.BackUpId, a.HasAutoAssignClaims, a.IsActive
from AppUser a
join AspNetUsers u on a.AspNetUserId = u.Id
left join AspNetUserRoles ur on u.Id = ur.UserId
left join AspNetRoles r on ur.RoleId = r.Id
I have only being able to get the exact same sql but with inner joins. I can't seem to get the two left joins. The code below here how I was able to generate the inner joins and also a fail attempt at generating the left joins.
SELECT [a].[AppUserId], [a].[FirstName], [a].[MiddleName], [a].[LastName], [a].[IsInternal], [a].[AspNetUserId], [a].[PictureLink], [a].[SignatureLink], [a].[PhoneNumber], [a].[Extension], [a].[FaxNumber], [a].[MobileNumber], [a].[Skype], [a].[SupervisorId], [a].[BackUpId], [a].[HasAutoAssignClaims], [a].[IsActive]
FROM [AppUser] AS [a]
INNER JOIN [AspNetUsers] AS [b] ON [a].[AspNetUserId] = [b].[Id]
INNER JOIN [AspNetUserRoles] AS [c] ON [b].[Id] = [c].[UserId]
INNER JOIN [AspNetRoles] AS [d] ON [a].[RoleId] = [d].[Id]
Code with inner join works but I want left joins....:
var query = (
//INNER JOIN
from a in _dbCtx.AppUser
join b in _dbCtx.Users
on a.AspNetUserId equals b.Id
////LEFT JOIN
join c in _dbCtx.UserRoles
on b.Id equals c.UserId
// // //LEFT JOIN (if you wanted right join the easiest way is to flip the order of the tables.
join d in _dbCtx.Roles
on a.RoleId equals d.Id
select new
{
AppUserId = a.AppUserId,
//Email = b.Email,
FirstName = a.FirstName,
MiddleName = a.MiddleName,
LastName = a.LastName,
IsInternal = a.IsInternal,
AspNetUserId = a.AspNetUserId,
PictureLink = a.PictureLink,
SignatureLink = a.SignatureLink,
PhoneNumber = a.PhoneNumber,
Extension = a.Extension,
FaxNumber = a.FaxNumber,
MobileNumber = a.MobileNumber,
Skype = a.Skype,
//Role = d.Name != null ? string.Empty :d.Name ,
SupervisorId = a.SupervisorId,
BackUpId = a.BackUpId,
HasAutoAssignClaims = a.HasAutoAssignClaims,
IsActive = a.IsActive
}).ToList();
Code with Left Join...which I am missing some concept doesnt work
what doesnt work is that on g2.RoleId equals d.Id into group3 line the g2 is not available. So how would I make c.RoleId available for my next left join? Basically after you group something you can no longer use it apparently.
var LeftJoin= (
//INNER JOIN
from a in _dbCtx.AppUser
join b in _dbCtx.Users
on a.AspNetUserId equals b.Id
////LEFT JOIN
join c in _dbCtx.UserRoles
on b.Id equals c.UserId into group2
from g2 in group2.DefaultIfEmpty() //makes it left join
join d in _dbCtx.Roles
on g2.RoleId equals d.Id into group3
from g3 in group3.DefaultIfEmpty()
select new
{
AppUserId = a.AppUserId,
Email = b.Email,
FirstName = a.FirstName,
MiddleName = a.MiddleName,
LastName = a.LastName,
IsInternal = a.IsInternal,
AspNetUserId = a.AspNetUserId,
PictureLink = a.PictureLink,
SignatureLink = a.SignatureLink,
PhoneNumber = a.PhoneNumber,
Extension = a.Extension,
FaxNumber = a.FaxNumber,
MobileNumber = a.MobileNumber,
Skype = a.Skype,
Role = g3.Name != null ? string.Empty :g3.Name ,
SupervisorId = a.SupervisorId,
BackUpId = a.BackUpId,
HasAutoAssignClaims = a.HasAutoAssignClaims,
IsActive = a.IsActive
}).ToList();
In case anyone comes to this question, thinking it hasn't been answered, the answer is currently buried in a comment chain after the question. I'm merely paraphrasing the key comments here.
The problem is that Entity Framework 7 is currently a release candidate and has some bugs. One of these bugs (Left Join doesn't work if the filter is composed on top) is causing the failure of the left join noted by the OP.
The solution, for now, is to revert to Entity Framework 6, or temporarily use a stored procedure or inline SQL until the bug is fixed.
If i understood you properly you problem is that EF is not generating LEft join. If yes then solution is pretty simple your Entities should have nullable property for instance
public class SomeClass
{
public int Id { get; set; }
public int? CategoryId { get; set; }
public Category Category {get;set:}
}
One option which is in my head
_dbCtx.SqlQuery<T>(SqlStringHEre).ToList()
Other option, and aspnet tables i would do it differently
var query = _dbCtx.AppUser
.Include(apu=>apu.AspNetUser)
.Include(apu=>apu.AspNetUser.Roles)
.Include(apu=>apu.AspNetUser.Roles.Select(r=>r.Role))
.ToList();
but here is problem as we talk in comments that IdentityUserRole does not have refference to role so lets fix that.
create class
public class UserToRole : IdentityUserRole<int>
{
public Role Role { get; set; }
}
Then extend your user class
public class YourUser : IdentityUser<int, IdentityUserLogin<int>, UserToRole, IdentityUserClaim<int>>
Now you can do what you want
_db.Users.Select(u=>u.Roles.Select(r=>r.Role.Name))
This is a work around that generates the data with a very bad query. It generate a series of calls to the database that does yield the same result set. However, it is definitely not the best query for the job. I am still waiting for RC2 and I will update the answer.
var query = (
//INNER JOIN
from a in _dbCtx.AppUser
join b in _dbCtx.Users
on a.AspNetUserId equals b.Id
from c in _dbCtx.UserRoles
.Where(x => b!=null && x.UserId == b.Id)
.DefaultIfEmpty()
from d in _dbCtx.Roles
.Where(x => a !=null && x.Id == a.RoleId)
.DefaultIfEmpty()
select new
{
AppUserId = a.AppUserId,
Email = b.Email,
FirstName = a.FirstName,
MiddleName = a.MiddleName,
LastName = a.LastName,
IsInternal = a.IsInternal,
AspNetUserId = a.AspNetUserId,
PictureLink = a.PictureLink,
SignatureLink = a.SignatureLink,
PhoneNumber = a.PhoneNumber,
Extension = a.Extension,
FaxNumber = a.FaxNumber,
MobileNumber = a.MobileNumber,
Skype = a.Skype,
Role = d.Name != null ? string.Empty :d.Name ,
SupervisorId = a.SupervisorId,
BackUpId = a.BackUpId,
HasAutoAssignClaims = a.HasAutoAssignClaims,
IsActive = a.IsActive
}).ToList();

How can I join tables with different data types using Entity Framework

With the situation of using Entity Framework,I want to join tables with two field in same value,but the fields are identified with different data types. For example,there is a field which the data type is 'Guid',but in another table the associated field is 'string' type. I am confused to achieve the goal. Can somebody give me some ideas.Here are my codes, emps.EmpGuid is a 'Guid' data type and flowCode.Object is a string:
DbSet<tb_Emp_Manager_Zbdl> dbEmp = zbdlcontext.Emp_Manager;
DbSet<Tb_Corp_CompanyInfo_Zbdl> dbCompany = zbdlcontext.Corp_CompanyInfos;
DbSet<Tb_FlowCode_Zbdl> dbFlowCode = zbdlcontext.FlowCodes;
DbSet<Tb_Emp_Post_Zbdl> dbEmpPost = zbdlcontext.Emp_Post;
var query = from emps in dbEmp
join companies in dbCompany on emps.CorpGuid equals companies.CorpUserGuid
join flowCode in dbFlowCode on new { EmpGuid = emps.EmpGuid.ToString(), AreaCode = areaCode } equals new { EmpGuid = flowCode.ObjectId, AreaCode = flowCode.AreaCode } into jFlowCodes
from flowCodes in jFlowCodes.DefaultIfEmpty()
join post in dbEmpPost on emps.EmpGuid equals post.EmpGuid into jPosts
from posts in jPosts.DefaultIfEmpty()
select new tb_Emp_Manager()
{
EmpGuid = emps.EmpGuid,
AreaCode = emps.AreaCode,
FlowCode = flowCodes.FlowCode,
corpName = companies.CorpName
};