I am trying use LINQ in a C# program to get information from a database. I have found a lot of examples showing basic to advanced queries, but i get a error when i try to build. See basic LINQ example below:
The class with the LINQ
public class StdFy
{
public object GetStdFy(DrillholeEntities ddb)
{
try
{
var myList = ((from t1 in ddb.DTM_QAQC_BLK_STD from t2 in ddb.DTM_STANDARDSASSAY.Where(x=> t1.STANDARDID==x.STANDARDID && t1.ASSAYVALUE==x.STANDARDVALUE)
select new
{
CHECKID = t1.CHECKID,
STANDARDID = t1.STANDARDID,
PRIORITY = t1.ASSAY_PRIORITY,
NAME = t1.ASSAYNAME,
ASSAYVALUE = t1.ASSAYVALUE,
STANDARDVALUE = t2.STANDARDVALUE,
STANDARDDEVIATION = t2.STANDARDDEVIATION,
NORMALIZACION = (t2.STANDARDVALUE- t1.ASSAYVALUE)/ t2.STANDARDDEVIATION,
LABJOBNO = t1.LABJOBNO,
LOADDATE = t1.RETURNDATE
})).OrderBy(x => x.LOADDATE).ToList();
return myList;
}
catch (Exception)
{
throw new NotImplementedException();
}
}
}
and then
DrillholeEntities ddb;
StdFy stdFy = new StdFy();
using (ddb = new DrillholeEntities())
{
IOrderedEnumerable<DTM_QAQC_BLK_STD> datosTodos;
datosTodos = stdFy.GetStdFy(ddb);
}
and when i buuild the project i get the error
Severity Code Description Project File Line Suppression State
Error CS0266 Cannot implicitly convert type 'object' to
'System.Linq.IOrderedEnumerable'.
An explicit conversion exists (are you missing a
cast?) Inspinia_MVC5 C:\Users\chachl9\Documents\Visual Studio
2015\Projects\MVC5_Full_Version\Inspinia_MVC5\Controllers\GraphsController.cs 55 Active
You are returning a list of objects of an anonymous type by
select new { ... }
thats may the reason why you use object as return type of your method.
Than you assign the return value to a specific type. Thats the reason why the exception ist thrown.
To get this work I would implement a new class which contains all your needed properties. Use it in
select new MyNewClass { Property1 = ...}
change the return type of your method from object to IEnumerable<MyNewClass>. Aswell the variable you assign the return value to.
You should also use PascalCase properties as mentioned by Gert Arnold in the comments.
Also mixing the select from in where LINQ syntax with the Lambda methods .Where(x => ...) make it hard to read.
Related
I have a table of doctors in my database. So I'm trying to get the list of the firstName of the doctors in my database.
In the ViewModel class I'm using this code to get it
public List DoctorsList ()
{
// string mainconn = Configuration
List ListOfDoctors;
using (var context = new GlabDbContext())
{
var result = (from c in context.Doctors
select c.LastName).ToList();
ListOfDoctors = result;
}
return ListOfDoctors;
}
I want to use this function like a method of my ViewModel class an it will have a return.
But I'm getting an error saying that:
Impossible to convert implicitely 'System.Collections.Generic.List into 'System.Windows.Documents.List'?
I try to cast the result like this
public List DoctorsList ()
{
// string mainconn = Configuration
List ListOfDoctors;
using (var context = new GlabDbContext())
{
var result = (from c in context.Doctors
select c.LastName).ToList();
**ListOfDoctors = (list)result;**
}
return ListOfDoctors;
}
but I get an error at the run time for the app.
How can I resolve the problem?
Your List ListOfDoctors appears to be really an
System.Windows.Documents.List ListOfDoctors;
and this is also the return type of your method.
Your var result really is
System.Collections.Generic.List<string> result
The two types are not compatible, meaning that you cannot cast one to the other (as the error message says).
I suspect you don't really want to return a Documents.List but a List<string> (containing just those names). So:
Remove a using System.Windows.Documents; from your file
Change all List to List<string>
You can try this like this:
System.Windows.Documents.List listx = new System.Windows.Documents.List();
foreach (var r in result)
{
listx.ListItems.Add(new ListItem(new Paragraph(new Run(r)));
}
Most probably you had an intention to use the IList or List<T>, but accidentally imported the System.Windows.Documents.List and all the later errors appeared because of that.
Please, take a moment and think what return type do you really need and if you want to return a collection of string elements then either use List<string> or IList as a return type:
public IList DoctorsList() // or return List<string> or IList<string> (generic version)
{
// string mainconn = Configuration
IList ListOfDoctors;
using (var context = new GlabDbContext())
{
var result = (from c in context.Doctors
select c.LastName).ToList();
ListOfDoctors = result;
}
return ListOfDoctors;
}
Shorter version (c# 8 compatable):
public IList DoctorsList() // or return List<string> or IList<string> (generic version)
{
using var context = new GlabDbContext();
return (from c in context.Doctors select c.LastName).ToList();
}
Remember:
You can do casting only with compatible types, which means that there should be either appropriate conversion operators defined for both types or a Baseā¶Derived class relationship should exist between types.
For more information:
About Casting and type conversions read here.
About Type conversion operators read here.
I am creating a reusable mapping expression from my EF entity to my BLL entity:
private Expression<Func<Person, bool>> GetNameFilter(string name)
{
return person => person.Profile.UserName == name;
}
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//Compilation Error
Owned = perk.Players.Any(GetNameFilter(name))
};
}
And I am getting a compilation error on the noted line. The error reads:
ICollection does not contain a definition for 'Any' and the best extension method overload 'Queryable.Any(IQueryable, Expression>)' requires a receiver of type 'IQueryable'
But this does not happen when I push this expression in directly:
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//No Compilation Error
Owned = perk.Players.Any(person => person.Profile.UserName == name)
};
}
Why is this happening? The type of both expressions is the same.
Using the LinqExpression solution found below, I am now getting the following error at runtime:
An exception of type 'System.InvalidCastException' occurred in LinqKit.dll but was not handled in user code
Additional information: Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.
internal FutureQuery<Perk> GetPlayerInfoPerks(string username)
{
return Master
.Perks
.VisiblePerks
.Select(Master.Perks.MapPerkPerk(username))
.Future();
}
Is this due to the use of the EntityFramework.Future library?
Why is this happening? The type of both expressions is the same.
The type of both expressions is not the same - they just look visually the same. The following is valid:
dbContext.Persons.Any(GetNameFilter(name))
and this is not:
perk.Players.Any(GetNameFilter(name))
Why? Because the first expects Expression<Func<...>> while the second - just Func<..> (the typical difference between IQueryable<T> and IEnumerable<T> methods with the same name). Hope you see the difference. When you type it directly, the C# compiler does its magic to emit one or the another, but when you do that manually, you are supposed to use the correct one.
The problem is addressed by LinqKit package with Invoke / Expand custom extension methods (and more generally with AsExpandable).
For your concrete example, the LinqKit solution could be like this:
using LinqKit;
...
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
// LinqKit requires expressions to be in variables
var nameFilter = GetNameFilter(name);
return Linq.Expr((Ef.Perk perk) => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
Owned = perk.Players.Any(p => nameFilter.Invoke(p))
}).Expand();
}
There are lots of possible duplicates for this post.But i tried most of thems, unfortunately my error still
happens.
Error is : Error 1 Cannot implicitly convert type 'System.Collections.Generic.List<Report.Business.ViewModels.InvoiceMaster>' to 'System.Collections.Generic.IList<ICSNew.Data.InvoiceHD>'. An explicit conversion exists (are you missing a cast?)
public IList<InvoiceHD> GetAllInvoiceMasterDetailsByInvoiceId(int InvoiceId)
{
var dbMstDtl = ireportrepository.GetAllInvoiceMasterDetailsByInvoiceId(InvoiceId);
var MstDtl = from mst in dbMstDtl
select new Report.Business.ViewModels.InvoiceMaster
{
ModifiedDate = mst.ModifiedDate,
SubTotal = Convert.ToDecimal(mst.SubTotal),
TotalDiscount = Convert.ToDecimal(mst.TotalDiscount),
VAT = Convert.ToDecimal(mst.VAT),
NBT = Convert.ToDecimal(mst.NBT),
AmtAfterDiscount = Convert.ToDecimal(mst.AmtAfterDiscount)
};
return MstDtl.ToList();
}
In some post i saw this thing solved when they use return MstDtl.AsEnumerable().ToList();
But in my case it also not working(getting errors)
Assuming InvoiceMaster derives from or implements InvoiceHD, and that you're using C# 4 and .NET 4 or higher, you can just use generic variance:
return MstDtl.ToList<InvoiceHD>();
This uses the fact that an IEnumerable<InvoiceMaster> is an IEnumerable<InvoiceHD> because IEnumerable<T> is covariant in T.
Another way to solve it would be to change the declaration of MstDtl to use explicit typing:
IEnumerable<InvoiceMaster> MstDtl = ...;
(I'd also suggest following regular C# naming, where local variables start with a lower-case letter, but that's a different matter.)
You are returning the wrong type. Your method signature says that you are returning a collection of InvoiceHD but you are actually returning a collection of InvoiceMaster
You are returning the wrong type
if InvoiceHD is a subtype of Report.Business.ViewModels.InvoiceMaster:
MstDtl.Cast<InvoiceHD>().ToList()
or if ICSNew.Data.InvoiceHD does not derive from Report.Business.ViewModels.InvoiceMaster then you can map your data manualy:
var MstDtl = from mst in dbMstDtl
select new InvoiceHD //return InvoiceHD instead of Report.Business.ViewModels.InvoiceMaster
{
ModifiedDate = mst.ModifiedDate,
SubTotal = Convert.ToDecimal(mst.SubTotal),
TotalDiscount = Convert.ToDecimal(mst.TotalDiscount),
VAT = Convert.ToDecimal(mst.VAT),
NBT = Convert.ToDecimal(mst.NBT),
AmtAfterDiscount = Convert.ToDecimal(mst.AmtAfterDiscount)
}
or change a return type of your function from InvoiceHD to
public IList<Report.Business.ViewModels.InvoiceMaster> GetAllInvoiceMasterDetailsByInvoiceId(int InvoiceId)
I am trying to return a list of an object that contains another object list as a databmember using linq. I've tried the examples shown but I keep getting ad different error with each attempt. One of which is as follows: LINQ to Entities does not recognize the method 'System.Collections.Generic.List1[SunGard.Tools.Notifications.LinkVariable] ToList[LinkVariable](System.Collections.Generic.IEnumerable1[SunGard.Tools.Notifications.LinkVariable])' method, and this method cannot be translated into a store expression.
I have an object (AlertMessageReturn) that contains some string datamembers as well as a list aof another object (List). I have a class that defines the LinkVarible and a table that contains the values. My query looks like this:
AlertMessagesQuery = from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new AlertMessageReturn()
{ PAM_ShortMessage = alertMessage.PAM_ShortMessage,
PAM_LongMessage = alertMessage.PAM_LongMessage,
PAM_LongMessageRemote = alertMessage.PAM_LongMessageRemote,
LinkVariables = (from linkVariable in this.context.AlertMessageLinks
from user in this.context.AlertMessageUsers
where user.PAMU_PAM_ID == linkVariable.PAML_PAM_ID && user.PAMU_UserId == UserId
select new LinkVariable()
{
Name = linkVariable.PAML_SessionVariableName,
Value = linkVariable.PAML_SessionVariableValue
})
};
The error is related to the type returned for linkvariables.
Please help.
I changed the code as follows:
LinkDataQuery = from linkData in this.context.AlertMessageLinks
from user1 in this.context.AlertMessageUsers
where user1.PAMU_PAM_ID == linkData.PAML_PAM_ID && user1.PAMU_UserId == UserId
select new LinkData
{
Name = linkData.PAML_SessionVariableName,
Value = linkData.PAML_SessionVariableValue
};
var links = LinkDataQuery.ToList();
AlertMessagesQuery = from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new AlertMessageReturn()
{ PAM_ShortMessage = alertMessage.PAM_ShortMessage,
PAM_LongMessage = alertMessage.PAM_LongMessage,
PAM_LongMessageRemote = alertMessage.PAM_LongMessageRemote,
LinkVariables = links
};
var AlertMessages = AlertMessagesQuery.ToList(); // this is where the error point to
if (AlertMessages.Any())
{
return AlertMessages;
}
The error I now get is:System.NotSupportedException: Unable to create a constant value of type 'SunGard.Tools.Notifications.LinkData'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
The LINQ to SQL engine cannot turn your sub-query to generate the LinkVariables into SQL. More importantly, SQL cannot return nested data sets like that.
Any time you get a message of type 'cannot be translated into a store expression' it is an indicator that you are doing something with your linq that is attempting to be translated into other statements (usually SQL). For example, if you say
....select new MyObject
{
Id = Guid.Parse( passedIdentity ),
....
}
while this is a totally valid C# statement you will get an error that Guid.Parse cannot be handled by linq. If it is possible to move the variables into external variables that are used inside the query then it would work. So you would do...
string name = linkVariable.PAML_SessionVariableName;
string nValue = ....
....
select New LinkVariable
{
Name=name,
Value=nValue
};
Also ... you do not need the closing parens on the Select New statement.
While LINQ to SQL can bring back object heirarchies, it can't project into types that aren't part of the model. Instead of projecting into the AlertMessageReturn type, try projecting into an anonymous type in the IQueryable portion of the code. Once you're done structuring your database query, force the results to come back (using AsEnumerable) and then project that into your AlertMessageReturn type. It's more overhead, but does work. Alternatively, you can use something like AutoMapper to translate your anonymous type into the result types.
AlertMessagesQuery =
from alertMessage in this.context.AlertMessages
where alertMessage.UserId=UserId
select new
{
alertMessage.PAM_ShortMessage,
alertMessage.PAM_LongMessage,
alertMessage.PAM_LongMessageRemote,
LinkVariables = from linkVariable in this.context.AlertMessageLinks
from user in this.context.AlertMessageUsers
where user.PAMU_PAM_ID == linkVariable.PAML_PAM_ID && user.PAMU_UserId == UserId
select new
{
Name = linkVariable.PAML_SessionVariableName,
Value = linkVariable.PAML_SessionVariableValue
})
};
var alertMessageResults =
from message in AlertMessagesQuery.AsEnumerable()
select new AlertMessageResult
{
PAM_ShortMessage = mesage.PAM_ShortMessage,
PAM_LongMessage = message.PAM_LongMessage,
PAM_LongMessageRemote = message.PAM_LongMessageRemote,
LinkVariables = (from variable in message.LinkVariables
select new LinkVariable { Name=variable.Name, Value = variable.Value})
.ToList()
};
return alertMessageResults.ToList();
ASP.NET 3.5 C#
I am joining two tables using Linq.
Table names are MapAssets and ExitPoint.
In Database they are related with 'has a relationship'
I am writing a function in my BLL to return the joined table
public List<ExitPoints> GetExitPointDetailsByProjectID(int iProjectID)
{
ctx = new CoreDBDataContext();
var exitPointDetails = from ma in ctx.MapAssets
join ep in ctx.ExitPoints
on ma.MapAssetID equals ep.MapAssetID
where ma.ProjectID == iProjectID
select new
{
//would like to have data from both tables here
ctx.MapAssets,
ctx.ExitPoints
};
return exitPointDetails.ToList();
}
This obviuosly doesn't work. And I dont know what to return at all.
All constraint I have for the return is to be able to be bound to a gridview.
is this the correct way? Or else whats the correct way?
You can't, or better, the only way is to return them boxed in a List of object, but this hugely complicates things, because you can't cast them to any type (of course it's anonymous) and you can only access their properties through reflection....
In cases like that, I'd highly suggest you to create a custom class.
EDIT:
On a side note...
If you were using .net 4, things would be easier because you could returns dynamic Type instead of object (look at this link to see dynamic's simplifications), but I'd prefer to create a custom class anyway.
Have a look at how to return anonymous types from Method.
http://forums.asp.net/t/1387455.aspx.
Copying the code from the link.
object ReturnAnonymous()
{
return new { Name="Faisal", City="Chakwal" };
}
// Application entry-point
void Main()
{
object o = ReturnAnonymous();
// This call to 'Cast' method converts first parameter (object) to the
// same type as the type of second parameter - which is in this case
// anonymous type with 'Name' and 'City' properties
var typed = Cast(o, new { Name="", City="" });
Console.WriteLine("Name={0}, City={1}", typed.Name, typed.City);
}
// Cast method - thanks to type inference when calling methods it
// is possible to cast object to type without knowing the type name
T Cast<T>(object obj, T type)
{
return (T)obj;
}
You can use the method mentioned below to return List and
List<object> lstAnonymousTypes = GetExitPointDetailsByProjectID(1);
foreach(object o in lstAnonymousTypes)
{
//Change it accordingly
var typed = Cast(o, new { new MapAssets() , new ExitPoints() });
}
Hope this helps not tried.
You can't return an anonymous type, you can only use an anonymous type in the scope of the method it's in. You could need to create a new class with MapAssets/ExitPoints properties and select a new instance of that class.
You are trying to return List ExitPoints and List of MapAssets which is not possible because you are getting the output from both tables ie ExitPoints and MapAssets. And it is also not possible to return an anonymous type. So in order to retrun the query create a class name ExMapClass with properties that you need as output of the queries. Now after executing the linq query which you have written iterate it ie
create list of newly created class
list newclass = new list ();
foreach( var result in ctx )
{
instantiate the created class
obj.Property1 = var.MapAssets;
obj.Property2 = var.ExitPoints;
newclass.add(obj);
}
now retrun the list of newlycreated class.
hope you got it.
Do you have to bind to this object after you've created it? If not then you can create an "persistent AnonymousType" class that stores the values in a dictionary and returns the property values with a method like:
string lastName AnonType.GetValue<string>("LastName");
int age AnonType.GetValue<int>("Age");
Here is a link to an excellent example. The author also has an example where he creates the "AnonymousType" from a datatable.
I have worked on a variation of this where I provide the ability to query a list of "AnonymousType" with the following syntax:
// Here's the query
var dept13 = anonAgents.AsQueryable()
.Where(x => x.Has("Department", Compare.Equal, 13);
// Here is how the List is constructed
private static AnonymousType ProvisionAgent(string name, int department)
{
return AnonymousType.Create(new
{
Name = name,
Department = department
});
}
private List<AnonymousType> CreateAnonAgentList()
{
var anonAgents = new List<AnonymousType>();
// Dave and Cal are in Department 13
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Dan Jacobs", 13, 44)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Calvin Jones", 13, 60)));
// Leasing = Dept 45
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stanley Schmidt", 45, 36)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Jeff Piper", 45, 32)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stewart Blum", 45, 41)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stuart Green", 45, 38)));
// HR = Dept 21
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Brian Perth", 21, 25)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Katherine McDonnel", 21, 23)));
return anonAgents;
}
Just use and ArrayList
public static ArrayList GetMembersItems(string ProjectGuid)
{
ArrayList items = new ArrayList();
items.AddRange(yourVariable
.Where(p => p.yourProperty == something)
.ToList());
return items;
}
wont this work ?
ctx = new CoreDBDataContext();
var exitPointDetails = from ma in ctx.MapAssets
join ep in ctx.ExitPoints
on ma.MapAssetID equals ep.MapAssetID
where ma.ProjectID == iProjectID
select Tuple.Create(ma, ep);
return exitPointDetails.ToList();