Entity Framework - sort by SQL function - c#

Is it possible to sort in Entity Framework by sql function from database?
I mean something like:
var xx = DbContext.Set<Article>()
.Where(x=>x.Name.Contains("X")).OrderBy("[dbo].[MySQLFunction]");

var xx = DbContext.Set<Article>()
.Where(x=>x.Name.Contains("X"))
.Select(x=> new
{
Article = x,
orderItem = SqlFunction.//Any function you want to use.
// Or may you want to use DbFunctions
})
.OrderBy(x=>x.orderItem);
Here is more information about DbFunctions and SqlFunctions
Update:
By the way, if you mean to use your custom SQLFunction then I advise you to make a computed column in your table and make this column use this SQLFunction then you could OrderBy or filter against this field using normal Linq queries

The only option I found - is something like bad workaround, and I guess this is limited to simple queries.
var objectContext = ((IObjectContextAdapter)DbContext).ObjectContext;
var query = (System.Data.Objects.ObjectQuery)objectContext.CreateObjectSet<User>().Where(u => u.Id != Guid.Empty);
var initialQueryString = query.ToTraceString();
var resultQueryString = initialQueryString + " order by [dbo].[MySQLFunction]";
//careful here, if you use MS SQL you need to use SqlParameter instead of NpgsqlParameter
var paramValues = new List<NpgsqlParameter>();
foreach (var param in query.Parameters)
{
paramValues.Add(new NpgsqlParameter(param.Name, param.Value));
}
var result = objectContext.ExecuteStoreQuery<User>(resultQueryString, paramValues.Cast<object>().ToArray()).ToList();

Related

Filter element from SQL Database table using LINQ

I'm trying to learn LINQ. I have
var mydata = from k in db.emp_mains select k.empname.Equals("me");
But after this statement i the auto complete wont complete the table fields name
foreach(var x in mydata)
{
---> Autocomplete not working Console.WriteLine(x.empname);
}
Why is this happening? Kindly advice.
Your condition need to go into where clause
var mydata = (from k in db.emp_mains
where k.empname.Equals("me")
select k
).ToList();
What you want is to filter with the where statement:
var myData = from k in db.emp_mains
where k.empname == "me"
select name
I much prefer the linq syntax like this for simple statements however:
var myDate = dc.emp_mains.where(w => w.empname == "me").Select(s => s.name).ToList();
Either way, you should get a list on names.

LINQ subquery returns brackets and fieldnames, how to get just the value?

My LINQ query is the following, I query two tables, Settlements and Bills which have a one to many relationship, in particular there can be one settlement with one or more bills.
var TheSettlements = from settlement in context_.Settlements
select new
{
asettlementid = settlement.SettlementId,
SqBills = string.Join(",",
(
from b in context_.Bills
.Where(b => b.SettlementId == settlement.SettlementId)
select new { b.BillMunicipalityId }
))
};
Now the trivial part (for me), is that I would like the bills concatenated, so after many hours of trial and error, I got my results but the Bills(BillMunicipalityId) are presented inside brackets including the fieldname, like this.
The way I export the data, to a txt to be more precise, is this.
foreach (var settlement in TheSettlements)
{
SettlementsText
.Append(settlement.asettlementid).Append(Delimiter)
.Append(settlement.SqBills.ToString()).Append(Delimiter)
.Append(Newline);
}
And the results I get in the txt.
3,{ BillMunicipalityId = f9e47f81-fc97-4008-b93d-d384230c53aa },
6,,
7,{ BillMunicipalityId = 8b66610a-20c1-4f47-9f37-489d1a8ce31a },{ BillMunicipalityId = 003d59d4-7bcb-4603-b42c-dc389dd8fb06 },{ BillMunicipalityId = 0070bb29-e3a1-4317-b5e2-3d1ef08dd20b },
How should I handle this to get only the values?
Just the GUID of every BillMunicipalityId, without the { BillMunicipalityId = } part.
I think rather than selecting as a new object you could just select the value like this:
var TheSettlements = from settlement in context_.Settlements
select new
{
asettlementid = settlement.SettlementId,
SqBills = string.Join(",",
(
from b in context_.Bills
.Where(b => b.SettlementId == settlement.SettlementId)
select b.BillMunicipalityId
))
};
Your Linq statement looks really strange to me. As it shows in the question you're mixing Linq with extensions methods.
If context is a DbContext which is going to the database, concating the results with string.Join won't work as this statement can't be translated to SQL code. If context however contains in memory data this may work. I advise however to not use string.Join within Linq unless you add a clear comment to the code, this Linq should never hit the database.
When this code will hit the database, you'll get an NotSupportedException with the message:
LINQ to Entities does not recognize the method 'System.String Join[Int32]'
The second thing I notice in your query, normally the one-to-many relation is known by the datamodel and you shouldn't need to join the results yourself.
The easiest way to solve this, is to use an intermediate query, which gets the results from the database and after running the query and getting the data into memory, perform the conversion with string.Join()
This would look like:
var TheSettlements =
from settlement in context_.Settlements
select new
{
asettlementid = settlement.SettlementId,
SqBills = (
from b in settlement.Bills
select b.BillMunicipalityId
).ToList(),
};
// Get the results in memory:
var results = TheSettlements.ToArray();
// Format the results:
var printResults = results.Select(s =>
s.asettlementid.ToString() + ", " + string.Join(", ",s.SqBills));

linq join on guid and string column

I'm new to linq. I need to run a query that joins two columns (AnonymousUser.AnonymousId being uniqueidentifier and comment.UserId being nvarchar(100)), something like below:
using (CommentEntities db = new CommentEntities())
{
// filteredComments is a query that is not run until the next .ToList()
IQueryable<Comment> filteredComments = this.CommentGetList(...);
var query = from comment in filteredComments
// following line is the syntax error, because columns' types don't match
join user in db.AnonymousUsers on comment.UserId equals user.AnonymousId into gj
from userNull in gj.DefaultIfEmpty()
select new CommentWithName
{
Comment = comment,
UserId = comment.UserId,
FirstName = (userNull == null ? "" : userNull.Name),
LastName = "",
Email = (userNull == null ? "" : userNull.Email)
};
return query.ToList();
}
First I was happy writing the query with .ToString() ! As it turns out that entity framework doesn't know how to translate it to sql. The same is true for Guid.Parse(string). Also new Guid(string) cannot be used in linq to entities (only parameterless constructors allowed)!
So after searching, I found out it's not possible doing such thing in EF 4.0! I migrated my code to a stored procedure that I'm not really happy about it.
Is it possible to tell entity framework to use a CAST in SQL?
Is there any solutions to this problem? Is there any way that I can bring the logic in code?
NOTE: I meant to do it in one GO. Otherwise one possible solution is to get Entities from first table, and put the Ids in a list and get entities from second table.
call toList() before applying those methods. Like:
var Product = db.Products.Where(p => p.ProductId == Guid.Parse("B4E913F9-166C-49BA-AADE-6DB889D1756F")).Single();
Would throw a
c# LINQ to Entities does not recognize the method "System.Guid Parse" (System.String)' method, and this method cannot be translated into a store expression
But this works:
var Product = db.Products.ToList().Where(p => p.ProductId == Guid.Parse("B4E913F9-166C-49BA-AADE-6DB889D1756F")).Single()
p.s.: I think you will lose lazyloading but you can do eagerloading with .Include before calling .ToList().
If your list is object list you could convert it to the type which has Guid as identifier, first create new anonymous type and then filter it base on UserId, sure UserId which is of type int, wont include in join:
int output = 0;
var secondList = list.Where(x=>!int.TryParse(x.UserID, out output))
.Select(x=>new {Comment = x, ID = new Guid(x.UserID))
.ToList();
Now you could run your query on db by using secondList.

LINQ vs context.entity.Where()

Are these two blocks exactly the same? Does one have any advantage over the other?
using (var context = new TRANSITEntities())
{
var result = context.Table1.Where(c => c.UserCode == "123");
}
using (var context = new TRANSITEntities())
{
var result = from c in context.Table1
where c.UserCode == "123"
select c;
}
Exactly the same.
You can verify this yourself by looking at the ToString()
string query1String, query2String;
using (var context = new TRANSITEntities())
{
var result = context.Table1.Where(c => c.UserCode == "123");
query1String = result.Expression.ToString();
}
using (var context = new TRANSITEntities())
{
var result = from c in context.Table1
where c.UserCode == "123"
select c;
var query2String = result.Expression.ToString();
}
Assert.AreEqual(query1String, query2String);
It should also be noted that result is NOT actually a result. It's a non-executed/enumerated IQueryable. Meaning it's like a SQL statement that hasn't been run yet (sort of). If you were to do
var t1 = result.ToArray()
var t2 = result.ToArray()
then the query would actually be executed twice. t1 and t2 are the REAL results (an in memory array)...not result. In other words, result should really be named query And further, the example you have above will never work...because if you call ToArray on the result outside of the using block, it will fail...because you can't run the query once the context is disposed:
using (var context = new TRANSITEntities())
{
var result = context.Table1.Where(c => c.UserCode == "123");
}
// throws exception:
var array = result.ToArray();
They're exactly the same. The compiler converts the query syntax to the lambda expression version before it resolves any methods.
Well the first selects from context.Table1, the second selects from context.LINTE. So they select from totally different collections.
Also the first selects on a UserCode column and the second on a CodeUsager column..
Apart from that (is the first just a translation of the second and you forgot to translate the second) the code is the same. The C# compiler will just translate the second query into the first one and they will behave identically.
If you are trying to select from different tables then it is different.
But if the tables are same then it is just the representation different.
There is no difference it is just the preference which way you like to code.
All the linq queries are converted to Lambda before creating the sql representation.
From Julia Lermans' book Programming Entity Framework:
The MSDN documentation says, “In general, we recommend query syntax
because it is usually simpler and more readable; however, there is no
semantic difference between method syntax and query syntax.”*
Therefore, using one over the other is a matter of style and personal
choice.

How to append a where clause to an Entity Framework ObjectSet

I would like to append a set of conditional where clauses onto the end of an ObjectSet. However, the clauses do not get executed and instead the original query is run, for example:
using (Entities context = new Entities()){
var q = context.AuditLogs;
q.Where(o => o.WebsiteId == 1);
}
The where clause is not executed and the full result set is returned
I could instead use IQueryAble as in:
var q = context.AuditLogs.AsQueryable();
q = q.Where(o => o.WebsiteId == 1);
However this loses me the power of being able to use .Include to eager load my related entities.
No, it won't. at any point before executing the query, you would still be able to cast it back to ObjectQuery<T> and invoke methods like Include on it:
var query = context.AuditLogs.AsQueryable();
query = query.Where(o => o.WebsiteId == 1);
var auditLog = ((ObjectQuery<AuditLog>)query).Include("yourNavPropertyName")
.ToList();
If your intention is to build up a criteria incrementally, then the other option would be to leverage EntitySQL with QueryBuilder methods:
var query = context.AuditLogs.Where("it.WebsiteId = 1");
query = query.Where("...");
var auditLog = query.Include("yourNavPropertyName")
.ToList();
Just some good old fashioned linq would suffice here. Assuming you had a property named SiteOwner you could accomplish what your trying to do with the below query
using (Entities context = new Entities()){
var webSites = from sites in context.AuditLogs.Include("SiteOwner")
where sites.WebSiteId == 1
select sites;
}

Categories