Linq2Db and string.join() - c#

I am using Linq2db in my big query with subqueries.
At the one place inside it, I want to use string.Join():
...
FullPath = string.Join(" -> ", GetPathQuery(db, c.Id).Select(pi => pi.Name))
...
But I have received an exception:
LinqException: 'Join(" -> ", value(RI.DAL.Categories.AdminCategoryPreviewDAL).GetPathQuery(value(RI.DAL.Categories.AdminCategoryPreviewDAL+<>c__DisplayClass4_0).db, c.Id).Select(pi => pi.Name))' cannot be converted to SQL.
I use Postgre SQL and it has the concat_ws function which is perfect for me. So I try to use it:
[Sql.Expression("concat_ws({1}, {0})")]
public static string JoinAsString(this IQueryable<string> query, string separator)
{
return string.Join(separator, query);
}
...
FullPath = GetPathQuery(db, c.Id).Select(pi => pi.Name).JoinAsString(" -> ")
...
But I was failed with the same exception.
The full source code of the GetPathQuery:
private IQueryable<CategoryPathItemCte> GetPathQuery(IStoreDb db, Guid categoryId)
{
var categoryPathCte = db.GetCte<CategoryPathItemCte>(categoryHierarchy =>
{
return
(
from c in db.Categories
where c.Id == categoryId
select new CategoryPathItemCte
{
CategoryId = c.Id,
ParentCategoryId = c.ParentId,
Name = c.Name,
SeoUrlName = c.SeoUrlName
}
)
.Concat
(
from c in db.Categories
from eh in categoryHierarchy.InnerJoin(ch => ch.ParentCategoryId == c.Id)
select new CategoryPathItemCte
{
CategoryId = c.Id,
ParentCategoryId = c.ParentId,
Name = c.Name,
SeoUrlName = c.SeoUrlName
}
);
});
return categoryPathCte;
}

can you try like this,
FullPath = string.Join(" -> ", GetPathQuery(db, c.Id).Select(pi => pi.Name).ToList());
More query friendly approach
GetPathQuery(db, c.Id).Select(pi => pi.Name)
.Aggregate(string.Empty, (results, nextString)
=> string.Format("{0} -> {1}", results, nextString));

Related

Counts of certain fields in linq query

This is my query, it works fine and gives me expected result;
var result2 = (from dt in disMudahaleTipiRepo
join dm in disMudahaleRepo on dt.Kodu equals dm.MudahaleKodu
join kr in kurumRepo on dm.CreatedKurumKodu equals kr.KurumKodu
join yu in userRepo on dm.CreatedBy equals yu.ID
group dt by new { yu.Ad, yu.Soyad, kr.KurumAdi } into grp
select new
{
AdSoyAd = grp.Key.Ad + " " + grp.Key.Soyad,
KurumAdi = grp.Key.KurumAdi,
KoduSayisi1 = grp.Select(s => s.Kodu).Where(w=>w== "401.030").Count(),
KoduSayisi2 = grp.Select(s => s.Kodu).Where(w=>w== "402.090").Count(),
KoduSayisi3 = grp.Select(s => s.Kodu).Where(w=>w== "406.020").Count(),
KoduSayisi4 = grp.Select(s => s.Kodu).Where(w=>w== "402.020").Count(),
KoduSayisi5 = grp.Select(s => s.Kodu).Where(w=>w== "406.070").Count()
...
});
only problem is there are 86 fields more(lol), so it will end up like that:
...
select new
{
AdSoyAd = grp.Key.Ad + " " + grp.Key.Soyad,
KurumAdi = grp.Key.KurumAdi,
KoduSayisi1 = grp.Select(s => s.Kodu).Where(w=>w== "401.030").Count(),
...
KoduSayisi91 = grp.Select(s => s.Kodu).Where(w=>w== "436.070").Count()
});
Instead of doing this, I tried to create a dictionary and keep as (Code, Number) its good in theory but how can I tell this to linq?
I don't think definition of entities is necessary here but let me share;
public class DisMudahaleTipi : Entity
{
public string Kodu { get; set; }
public string Name { get; set; }
}
public class DisMudahale : AuditableEntity
{
public string MudahaleKodu { get; set; }
}
You could try to use a subquery, but I don't have a database at hand to test if the following works:
var keys = ["401.300", .. ];
var result = (from dt in disMudahaleTipiRepo
join dm in disMudahaleRepo on dt.Kodu equals dm.MudahaleKodu
join kr in kurumRepo on dm.CreatedKurumKodu equals kr.KurumKodu
join yu in userRepo on dm.CreatedBy equals yu.ID
group dt by new { yu.Ad, yu.Soyad, kr.KurumAdi } into grp
select new
{
AdSoyAd = grp.Key.Ad + " " + grp.Key.Soyad,
KurumAdi = grp.Key.KurumAdi,
Kudos = (from key in keys
select new
{
Key = key,
Amount = grp.Count(w => w.Kudo == key)
}).ToList(),
}).ToList();
Note: In addition to the subquery I changed Select(s=>s.Kudo).Where(w=>w=="...").Count() to reduce Linq complexity and improve performance.

LINQ to Entities does not recognize the method 'System.Collections.Generic.Dictionary`2[System.Int32,System.String] ToDictionary

I am trying to retrieve list of EmployeeDTO from DB which are stored in Employee table. Every employee can have one or more specialty. Specialty are stored in OrganizationSpecialtyType. Employee and OrganizationSpecialtyType are related with "many-to-many" via EmployeeSpecialty table.
I'm using the following query for that, and got an exception like in title:
var q = _context.Employee.Where(p => employeeEMIIDs.Contains(p.EmployeeID))
.Select(p => new EmployeeDTO
{
EmployeeID = p.EmployeeID,
GenderTypeID = p.GenderTypeID,
FirstName = p.FirstName,
LastName = p.LastName,
Name = p.Name,
MiddleName = p.MiddleName,
DOB = p.DOB,
Suffix = p.Suffix,
Title = p.Title,
Specialty = p.EmployeeSpecialty
.ToDictionary(d => d.OrganizationSpecialtyType.SpecialtyTypeID, d => d.OrganizationSpecialtyType.Name)
}
);
In the EmployeeDTO class the property Specialty is type public Dictionary<int, string>.
If I execute this query, everything works normally:
var spec = _context.Employee.Where(p => p.EmployeeID == -9070).FirstOrDefault()
.EmployeeSpecialty.ToDictionary(d =>
d.OrganizationSpecialtyType.SpecialtyTypeID,
d => d.OrganizationSpecialtyType.Name);
How I can solve my first query to obtain EmployeeDTO with specialties?
Thanks.
You can select to anonymous type first, then set the dictionary later.
var q = _context.Employee.Where(p => employeeEMIIDs.Contains(p.EmployeeID))
.Select(p => new
{
Employee = new EmployeeDTO
{
EmployeeID = p.EmployeeID,
GenderTypeID = p.GenderTypeID,
FirstName = p.FirstName,
LastName = p.LastName,
Name = p.Name,
MiddleName = p.MiddleName,
DOB = p.DOB,
Suffix = p.Suffix,
Title = p.Title
},
Specialty = p.EmployeeSpecialty
.Select(d => new
{
d.OrganizationSpecialtyType.SpecialtyTypeID,
d.OrganizationSpecialtyType.Name
})
})
.AsEnumerable()
.Select(a =>
{
a.Employee.Specialty = a.Specialty
.ToDictionary(d => d.SpecialtyTypeID, d => d.Name);
return a.Employee;
});

MySql Linq to SQL conver int to string

Hello I have a MySQL and LINQ to SQL task to convert Int value from DB to String,
toString() is not supported by MySql, and I am getting error about it.
var data = (from o in ObjectContext.MyTable.Where(d => d.a == a)
select new MyObject
{
Id = o.Id,
StringProperty = o.intColumn.ToString()
});
SqlFunction class is not suported for MySql.
You can try to convert the results to Enumerable and then query on it:
var data = (from o in ObjectContext.MyTable.Where(d => d.a == a)
select new MyObject
{
Id = o.Id,
StringProperty = o.intColumn.ToString()
}).AsEnumerable();
You could fetch all the data by adding AsEnumerable() to the table, or you could do the fetch first, then the conversion later - if I'm not mistaken, this should produce a slightly lighter SQL call:
var tempData = (from o in ObjectContext.Where(d => d.a == a) select o);
var converted = (from o in tempData.AsEnumerable()
select new MyObject
{
Id = o.Id,
StringProperty = o.intColumn.ToString()
});
Alternatively, write it all in one go by using the first part as a sub query:
var data = from x in
(from o in ObjectContext.Where(d => d.a == a) select o)
.AsEnumerable()
select new MyObject
{
Id = x.Id,
StringProperty = x.intColumn.ToString()
});
int to string in Entity Framework
also had supported a great solution you can refer. By this method you can change you source as the following.
var data = (from o in ObjectContext.MyTable.Where(d => d.a == a)
select new MyObject
{
Id = o.Id,
StringProperty = SqlFunctions.StringConvert((double)o.intColumn)
});

Concat or Join list of "names" in Linq

Using WCF RIA I have a query that returns a Query of names
public class WitnessInfo
{
[Key]
public Guid WCFId { get; set; }
public string witnessName { get; set; }
public string AllNames {get; set;}
}
Here's my Linq Query
[Query]
public IQueryable<WitnessInfo> getWitnessInfo(int? id)
{
IQueryable<WitnessInfo> witnessQuery = from witness in this.Context.witness
where witness.DAFile.Id == id
select new WitnessInfo
{
WCFId = Guid.NewGuid(),
witnessName = witness.Person.FirstName,
};
return witnessQuery;
}
I want to take all the names and return them in a single string i.e "John, James, Tim, Jones". Tried taking AllNames and looping through but that didn't work. Any suggestions?
First grab all of the information that you need in a single query, then use String.Join to map the collection of names to a single string:
var firstQuery = from witness in Context.witness
where witness.DAFile.Id == id
select new
{
WCFId = Guid.NewGuid(),
witnessName = witness.Person.FirstName,
Names = Context.witness.Select(w => w.FirstName),
})
.AsEnumerable(); //do the rest in linq to objects
var finalQuery = from witness in firstQuery
//do the string manipulation just once
let allNames = string.Join(", ", witness.Names)
select new WitnessInfo
{
WCFId = witness.WCFId,
witnessName = witness.witnessName,
AllNames = allNames,
});
By having the AllNames property in the WitnessInfo class, it is seems like you want each WitnessInfo object to contain the all of the squence names again and again repeatedly, and if this is your case then do it like that:
var names = (from witness in this.Context.witness
select witness.Person.FirstName).ToArray();
var allNames = string.Join(", ", names);
IQueryable<WitnessInfo> witnessQuery = from witness in this.Context.witness
where witness.DAFile.Id == id
select new WitnessInfo
{
WCFId = Guid.NewGuid(),
witnessName = witness.Person.FirstName,
AllNames = allNames
};
You can concatenate like this:
string.Join(", ", getWithnessInfo(666).Select(wq => wq.witnessName))
this.Context.witness.Select(a => a.Person.Firstname).Aggregate((a, b) => a + ", " + b);

Linq to Entities - NotSupportedException - dynamic type - string.Format

I'm making the switch from Linq-to-SQL to Linq-to-Entities and in the process of conversion came across the error "LINQ to Entities does not recognize the method 'System.String Format(System.String, System.Object, System.Object)' method, and this method cannot be translated into a store expression". The following code is the culprit. I understand that this has to do the with dynamic type generation I am using below. How can I still use the dynamic type and use L2E?
var query = _db.Persons.Where(p => p.PersonId == PersonId);
if (query.Count() > 0)
{
var data = query.Join(_db.Users, p => p.UserId, u => u.UserId, (p, u) => new
{
Id = p.PersonId,
Name = string.Format("{0} {1}", p.FirstName, p.LastName),
Phone = p.Phone,
Email = u.Email
}).Single();
return data;
}
EDIT:
OK, feel a little stupid after #John Hartsock showed me the simple solution...
What if I wanted to do some more complex string manipulation?
Why not this?
var query = _db.Persons.Where(p => p.PersonId == PersonId);
if (query.Count() > 0)
{
var data = query.Join(_db.Users, p => p.UserId, u => u.UserId, (p, u) => new
{
Id = p.PersonId,
Name = p.FirstName + " " + p.LastName,
Phone = p.Phone,
Email = u.Email
}).Single();
return data;
}
Here is a good link for you
http://msdn.microsoft.com/en-us/library/cc716715.aspx

Categories