I use linq to access a table from my DB using Entity Framework
MyDBEntities context = new MyDBEntities;
int id = 111;
var item = context.MyTable.Where(i => i.id == id).Single();
This works fine but now I create a method I wish to use instead of the id check:
bool AreNear(string Adress, object Adress)
I'd like to use that way
string adress = "...";
var item = context.MyTable.Where(i => AreNear(i.adress,adress) ).Single();
but I get an error at the execution saying I can't use the method in my query
is there a way to make it work?
Unfortunately, there is no way to make it work.
The reason for this is that the LINQ query isn't really executed as .NET code but it is translated into SQL by the EF provider. This EF provider doesn't know how to translate AreNear into SQL, so it fails.
Related
I want to get list of records from an entity model (I'm using EF version 5) with a particular accountID. I'm being supplied with the tableName string (this has to be dynamic) and the accountID. I'm trying the following 2 methods but none of them is working (giving me errors on the IQueryable object 'table':
PropertyInfo info = _db.GetType().GetProperty(tableName);
IQueryable table = info.GetValue(_db, null) as IQueryable;
var query = table.Where(t => t.AccountID == accID)
.Select(t => t);
List <object> recList = ( from records in table
where records.AccountID == accID
select records).ToList<object>();
The var query = table.Where(....).Select(...) is the correct move as it allows reflection for the query builder at runtime. However, t.AccountID is an error because of the type of t remains unknown.
I've previously used a similar approach in LINQ to SQL, using System.Linq.Expressions.Expression, e.g.:
// NOT TESTED
var table=context.GetTable(dynamicTableName);
var theT=table.Experssion; // actually, I forget. DynamicExpression or MemberBinding? or
var theField=Expression.Field(theT, "AccountID"); // or dynamic name
var query=table.Where(Expression.Equal(theField, accID);
var recList=query.ToList<object>();
If your object has a common interface there is a simpler syntax:
IQueryable<MyInterface> table = context.GetTable("table") as IQueryable<MyInterface>;
var recList=from r in table
where table.AccountID == ac // if your AccountID is on MyInterface
select table;
If you only have a few tables to support, you could do this as well:
IQueryable<MyInterface> table;
if("table1"==tableName)
table=_db.table1
elseif("table2"==tableName)
table=_db.table2
elseif("table3"==tableName)
table=_db.table3
else
throw exception
I built a DynamicRepository for a project I am working on. It uses generic methods exposed through EF along with dynamic linq. It might be helpful to look at that source code here:
https://dynamicmvc.codeplex.com/SourceControl/latest#DynamicMVC/DynamicMVC/Data/DynamicRepository.cs
You can query the entity framework metadata workspace to get the type for a given table name. This link might help:
Get Tables and Relationships
In my ASP.NET MVC 5 application I want to list the roles of a user. I downloaded some samples that seem to be broken. Basically I want both the role ID and role name of the roles of a selected user (not the current user!).
ApplicationUser.Roles gives me an IdentityUserRole object with only RoleId and UserId.
ApplicationDbContext.Roles gives me an IdentityRole with RoleId, RoleName etc. of ALL application roles.
So what I want is a result set with the intersection of both sets while retaining full role information so that I can use both its role ID and role name.
I tried Intersect() but that didn't work because both objects are of different type. I tried the dumb style of iterating but got an exception saying the DAta Reader was already active so I am stumped :(
I tried the following on LinQPad (with the appropriate conenctions and namespaces):
string UserName = "user#email.com";
ApplicationDbContext ctx = new ApplicationDbContext();
var allroles = ctx.Roles.OrderBy(r => r.Id);
allroles.Dump(); // dumps well, 6 roles
ApplicationUser user = ctx.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var myroles = user.Roles;
myroles.Dump(); // dumps well, 3 roles
IEnumerable<IdentityRole> list = from roles in allroles
join uroles in myroles
on roles.Id equals uroles.RoleId
select roles;
list.Dump(); // exception
And while the query seems to produce no error during execution, its dumping does regardless of whether I use Dump() or an explicit foreach (IdentityRole item in list). The error I get in this case is
"Unable to reate a constant value of type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole'. Only primitive types or enumeration types are supported in this context".
The only problem here is that you are not calling ToList() method which execute the query immediately (everything will be held in the memory).
For better understanding - ToList() method converts an IEnumerable<T> to a List<T>.
So, your code will look like this:
var allroles = ctx.Roles.OrderBy(r => r.Id).ToList();
var myroles = user.Roles.ToList();
You could use a combination of the two approaches you tried, where you get roles from the context that are present in the ApplicationUser's Roles property...
var roles = ApplicationDbContext.Roles
.Where(ar =>
ApplicationUser.Roles
.Select(ur =>
ur.RoleId)
.Contains(ar.RoleId));
You can do this way :
var rolesList = allroles.ToList().Join(myroles.ToList(),
left => left.Id,
right => right.RoleId,
(left,right) => left);
This way it is working for me for different scenario.
You're trying to join an in-memory list, myroles, with an IQueryable, allroles, which produces a new IQueryable: list. However, this new IQueryable is translated into SQL, so myroles must be translated into SQL as well. This is not supported for lists of non-primitive types.
The solution is to join two IQueryables:
var myroles = ctx.Users.Where(u => u.UserName == UserName).SelectMany(u => u.Roles);
var list = from role in allroles
join urole in myroles
on role.Id equals urole.RoleId
select role;
It's an exercise of EF code-first. There's a simple method. I want to get the Entity SQL command text generated by object services.
(MyDbContext is derived form DbContext. Person is a POCO class.)
using (MyDbContext context = new MyDbContext())
{
var query = context.Set<Person>().FirstOrDefault(p => p.Age == 1);
Console.WriteLine(query.Name);
var objquery = query as ObjectQuery;
if (objquery != null)
Console.WriteLine(objquery.CommandText);
}
I used to get native SQL command text by ObjectQuery.TraceString in LINQ to Entity. Now, what I need is Entity-SQL statement, NOT native SQL statement.
But, I can't cast the query from IQueryable<Person> to ObjectQuery or ObjectQuery<Person>.
I tried to get members of DbQuery by reflection. It seems that DbQuery hasn't any property about command text or trace string.
Thanks
My suggestion for what you want is using Dynamic Linq. The library (part of the Linq Samples) includes many IQueryable extensions that return Linq.DataQuery objects. Once you consume the DataQuery you'll have the expected object.
var testQuery =
db.Cases.
Where("KeyID > 1").
Take(1);
foreach (var r in testQuery)
{
Console.WriteLine(r);
}
Then, you can check against your query as such.
testQuery.Expression
testQuery.Provider
These will give you:
{Table(Case).Where( => (.Keyid > 1)).Take(1)}
System.Linq.Expressions.Expression {System.Linq.Expressions.MethodCallExpression}
-and-
{SELECT TOP (1) [t0].[Keyid], [t0].[FileNo], [t0].[MatterType], [t0].[LoanNo], [t0].[Investor], [t0].[LoanType], [t0].[Client], [t0].[ClientFileNo], [t0].[ClientStatus], [t0].[Mortgagor], [t0].[County], [t0].[PropertyStreet1], [t0].[PropertyStreet2], [t0].[PropertyCity], [t0].[PropertyState], [t0].[PropertyZipcode], [t0].[Status], [t0].[BoxNo], [t0].[InsurerLoanno], [t0].[InvestorLoanno], [t0].[insurer_name_id], [t0].[OldSystemKey], [t0].[FinalBilling], [t0].[HoldBilling], [t0].[LastModified], [t0].[PiggyLoanNo], [t0].[CurrComentID], [t0].[LockEFILE], [t0].[MSJAmount], [t0].[Created], [t0].[Locked], [t0].[FinalBillingDate], [t0].[HoldBillingDate], [t0].[CreatedBy], [t0].[Stage], [t0].[PriorStage], [t0].[DefendantUpdated], [t0].[VestingCode], [t0].[FileSource], [t0].[SubVestingCode], [t0].[AttorneyAssigment], [t0].[VoluntarySurrender], [t0].[FNMARisk], [t0].[Source], [t0].[REO_ID], [t0].[WTI_ID], [t0].[CaseDismissed], [t0].[REO_CompanyID], [t0].[SubMattertype], [t0].[VendorCode], [t0].[SubType]
FROM [dbo].[Cases] AS [t0]
WHERE [t0].[Keyid] > #p0}
System.Linq.IQueryProvider {System.Data.Linq.DataQuery<CMSDEVMapping.Case>}
You can also verify your type in the loop:
r.GetType() {Name = "Case" FullName = "CMSDEVMapping.Case"} System.Type {System.RuntimeType}
I'm using a LINQ to CRM from Advanced Developer Extension for MS CRM 4.0. It works fine with direct queries. But I've got a problem when query looks like this:
var connectionString = #"User ID=u; Password=p; Authentication Type=AD; Server=http://crm:5555/UO";
var connection = CrmConnection.Parse(connectionString);
var dataContext = new CrmDataContext(connection);
var data = from u in dataContext.Accounts
select new
{
Id = u.AccountID,
Name = u.AccountName,
};
var r = from n in data
where n.Name.StartsWith("test")
select new
{
Id = n.Id
};
r.Dump();
it throws an InvalidOperationException "Cannot determine the attribute name."
It's fine when a condition is directly in first query:
var data = from n in dataContext.Accounts
where n.AccountName.StartsWith("test")
select new
{
Id = n.AccountID,
Name = n.AccountName,
};
I cannot find any useful information about this kind of error. Is it a bug in Xrm Linq Provider?
Thanks in advance for any help.
Try eager loading the initial query with a ToList() so the latter query over your anonymous type is then evaluated locally. I get this is far from ideal if you have a lot of accounts but it'll prove the point. You essentially have a solution anyway in the last statement.
This is because the first query isn't executed at all until you call .Dump() at which point the entire expression including the second query is evaluated as one (deferred execution) by the provider which then looks for an attribute of Name.
I have a simlar requirement where in i have 3 main entities in ADO.NET entity model... I am building a framework wherein basedon incoming XML root element i have to create an instance of specific entity using reflection and set its properties..
But when it comes to child entities.. I am not able to use LINQ queries on it as the type is not known at design time. PropertyInfo.GetValue gives me an object on which i can not run LINQ queries (even when i typecast it to IQueryable or IEnumerable). I am not even able to typecast it at design time as that would be kind of hardcoding and will fail my generic framework purpose.
I tried to use dynamic keyword.. but on that too i can not write LINQ queries.. it gives a message that LINQ queries are not supported on dynamic dispatch model.!!!
Can someone help..
Regards Badal
Like #Yuriy Faktorovich recommended, dynamic LINQ may be your best shot.
Another option you have is to dynamically build expression trees and execute your expression via reflection. Keep in mind that this is not easy and may take a little time to wrap your head around the expression API, but for simple expression it's not too bad.
Example: Say you want to replicate this expression:
p => p.FirstName == firstName
You can build the expression tree as follows:
var myType = Type.GetType("Person"); // <-- Find your type based on XML
var firstName = "John";
var param = Expression.Parameter(myType, "p");
var firstNameProperty = Expression.Property(param, "FirstName");
var constantExpression = Expression.Constant(firstName);
var equalsExpression = Expression.Equal(firstNameProperty, constantExpression);
var lambda = Expression.Lambda(equalsExpression, param);
The lambda will have a runtime type of Expression<Func<Person,bool>> which you can then pass to any IQueryable implementation.
UPDATE
Then to dynamcially call some method on your IQueryable you can do something similar to the following:
var queryableType = typeof(Queryable);
var whereMethod = queryableType.GetMethod("Where", BindingFlags.Public | BindingFlags.Static);
var parameters = new object[] { query, lambda }; // query is your IQueryable object
var list = whereMethod.Invoke(null, parameters);