I use the code below to get records from two tables but I want to have the result in a List. I used the code below, but this error occured:
Cannot implicitly convert type
System.Collections.Generic.List<AnonymousType#1> to
System.Collections.Generic.List<QuickRoutes.DAL.Route>
public List<Route> GetAllForUser(Guid userId)
{
// var result = new List<Route>();
aspnetdbDataContext aspdb = new aspnetdbDataContext();
List<Route> result = (from r in aspdb.Routes
where r.UserId == userId
join t in aspdb.TrackPoints on r.RouteId equals t.RouteFK
select t.TrackPointId,t.RouteFK,t.TrackTime,t.Longitude,t.Latitude,t.Elevation, r.SourceName).ToList();
return result;
}
EDIT:
I want to match my query with this class:
namespace QuickRoutes.Entities
{
public enum RouteType
{
Route, Waypoints, Track
}
public sealed class Route
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public List<TrackPoint> TrackPoints { get; set; }
public Guid UserId { get; set; }
public string GpxData { get; set; }
public RouteType RouteType { get; set; }
public Route(int id)
{
Id = id;
TrackPoints = new List<TrackPoint>();
}
......
but if I change my code to this one,It doesn't work too
List<Route> result = (from r in aspdb.RouteLinqs
where r.UserId == userId
join t in aspdb.TrackPointlinqs on r.RouteId equals t.RouteFK
select r).ToList();
to be honest I want to change this function that is written with SQL to LINQ,have any better idee?
namespace QuickRoutes.Entities
{
public enum RouteType
{
Route, Waypoints, Track
}
public sealed class Route
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public List<TrackPoint> TrackPoints { get; set; }
public Guid UserId { get; set; }
public string GpxData { get; set; }
public RouteType RouteType { get; set; }
public Route(int id)
{
Id = id;
TrackPoints = new List<TrackPoint>();
}
......
It's because your projection (what you're selecting) isn't the same as a Route (what you're trying to return);
If you wish to return a Route Change your select to:
select r
If you wish to return your joined projection, you'l have to create a new type, and return that:
e.g:
public class RouteTrack
{
public TrackPointId ...
public RouteFK ...
public TrackTime ...
}
And return a List<RouteTrack> from your method, and change your select to:
select new RouteTrack { TrackPointId = t.TrackPointId .... }
Since your query selects properties from two different tables, it obviously no longer returns objects of type Route, but a new type of object (an anonymous type).
If you want to return this new type, you need to define it explicitly, then return the data using this type.
public class MyClass
{
public MyClass(int trackPointId, DateTime trackTime, ...)
{
TrackPointId = trackPointId;
TrackTime = trackTime;
...
}
public int TrackPointId { get; set; }
public DateTime TrackTime { get; set }
...
}
List<MyClass> result = (from r in aspdb.Routes
where r.UserId == userId
join t in aspdb.TrackPoints on r.RouteId equals t.RouteFK
select new MyClass(t.TrackPointId,t.RouteFK,t.TrackTime,t.Longitude,t.Latitude,t.Elevation, r.SourceName);
I have faced the same. The issue here is that you are creating an anonymous type that contains fields from both the Route and aspdb.TrackPoints.
Hence you cannot cast this to List.
This is a mapping problem.
To resolve this you need to create a newcustom class that contains all the fields/properties that you are getting out from the query.
Let's say you create a custom class say RouteMapper then map using code like
select new RouterMapper
{
RouteMapper.TrackPointId = t.TrackPointId, RouteMapper.RouteFK=t.RouteFK, RouteMapper.SourceName = r.SourceName
}
This way now you return List< RouteMapper>.
Related
I've got a many to many relationship between Tariff and Insurance. Here the classes:
public class Insurance
{
public int ID { get; set; }
public string Name { get; set; }
public bool Deleted { get; set; }
public virtual ICollection<Tariff> Tariffs { get; set; }
public override bool Equals(object obj)
{
Insurance ins = obj as Insurance;
if (ins != null)
{
return ins.ID == ID;
}
return false;
}
}
public class Tariff
{
public int ID { get; set; }
public string Code { get; set; }
public decimal MinPrice { get; set; }
public bool Delete { get; set; }
public virtual ICollection<Insurance> Insurances { get; set; }
}
Now I want to select all the Tariff objects where the property Insurances contains an Insurance where the ID property equals the given variable. For this I've written this code:
public IEnumerable<Tariff> GetFilteredPublished(int insuranceID)
{
return (from t in dbSet
where t.Insurances.Contains(insuranceID)
select t).ToList();
}
This doesn't work because insuranceID is not an Insurance. When I use this code:
public IEnumerable<Tariff> GetFilteredPublished(int inscuranceID, int interventionID)
{
Insurance ins = new Insurance() { ID = inscuranceID };
return (from t in dbSet
where t.Insurances.Contains(ins) && t.Intervention.ID == interventionID
select t).ToList();
}
Gives me this exception:
Unable to create a constant value of type Insurance. Only primitive types or enumeration types are supported in this context.
Notes by the code:
On code below you could read what the dbSet is.
internal Context context;
internal DbSet<Tariff> dbSet;
public TariffService() // the `TariffService` class is the place where I call
// `GetFilteredPublished`
{
context = new Context();
dbSet = context.Set<Tariff>();
}
I'm using LINQ and Entity Framework.
How could I do this?
By a comment of #Federico I've found the answer:
return (from t in dbSet
where t.Insurances.Any(i => i.ID == insuranceID) && t.Intervention.ID == interventionID
select t).ToList();
Any(): Determines whether any element of an IQueryable<T> sequence exists or satisfies a condition.
Source: learn.microsoft.com
I have three generic lists and I am trying to combine and get them into one (List<One>). I am not sure how to use LINQ group by on different lists. I want to group by AccountCode, AccountDate, and SalesCode; and sum the amount.
public class One
{
public string AccountCode { get; set; }
public DateTime AccountDate { get; set; }
public string SalesCode { get; set; }
public decimal? Amount { get; set; }
}
public class Two
{
public string AccountCode { get; set; }
public DateTime AccountDate { get; set; }
public string SalesCode { get; set; }
public decimal? Amount { get; set; }
}
public class Three
{
public string AccountCode { get; set; }
public DateTime AccountDate { get; set; }
public string SalesCode { get; set; }
public decimal? Amount { get; set; }
}
List<One> oneList = new List<One>();
List<Two> twoList = new List<Two>();
List<Three> threeList = new List<Three>();
This is the sample query I have, which is not working. Note: I have not included List<Three>.
from first in oneList
join second in twoList
on first.AccountCode equals second.AccountCode
where
(first.AccountDate.Date == second.AccountDate.Date && first.SalesCode == second.SalesCode)
select new
{
first.AccountCode,
first.AccountDate,
first.SalesCode
first.Amount,
second.Amount
}).Distinct()
group bill by new { bill.AccountCode, bill.AccountDate, bill.SalesCode }
into groupedList
select new
{
groupedList.Key.UAN,
groupedList.Key.AccountDate,
Amount = groupedList.Sum(a => a.Amount)
};
As mentioned in the comment, the first thing you'll need is a common type so that the 3 lists can be joined into a single list. That could be a base class or an interface as I've shown here.
public interface IAccount
{
string AccountCode { get; set; }
DateTime AccountDate { get; set; }
string SalesCode { get; set; }
decimal? Amount { get; set; }
}
public class One : IAccount
{
// ...
}
public class Two : IAccount
{
// ...
}
public class Three : IAccount
{
// ...
}
Once that's in place, then it's easy to combine your 3 lists into one like this:
var allList = oneList.Cast<IAccount>().Union(twoList).Union(threeList);
From there, the group by becomes much simpler as well. When using LINQ to group by multiple fields, you'll want an IEqualityComparer class that looks like this:
public class AccountComparer : IEqualityComparer<IAccount>
{
public bool Equals(IAccount x, IAccount y)
{
return x.AccountCode == y.AccountCode &&
x.AccountDate == y.AccountDate &&
x.SalesCode == y.SalesCode;
}
public int GetHashCode(IAccount obj)
{
return (obj.AccountCode + obj.AccountDate + obj.SalesCode).GetHashCode();
}
}
The group by call is then one line:
var groups = allList.GroupBy(a => a, new AccountComparer());
Alternatively, you could create an AccountKey class that only has the 3 key fields and return that from the keySelector lambda. That feels a little cleaner, but is a bit more code.
From there, you can select the sums like this:
var amountSums = from g in groups
select new
{
g.Key.AccountCode,
g.Key.AccountDate,
g.Key.SalesCode,
Amount = g.Sum(a => a.Amount)
};
I have a database with two tables (UserData) and (UserDetails). I use the LINQtoEntities.
The issue here is that in the LINQ query is not accepted:
Details = c.ToList<UserDetails>()
Error is:
Instance argument: cannot convert from 'System.Collections.Generic.IEnumerable<mynamespace.UserDetails>' to 'System.Collections.Generic.IEnumerable<System.Collections.IEnumerable>'
public class UserData
{
public int Index{ get; set; }
public string Name{ get; set; }
public string PersonalNo { get; set; }
public <List<UserDetails>> Details { get; set; }
}
public struct UserDetails
{
public int Age;
public string profession;
public string gender;
}
public IEnumerable<Userdata> GetUserData()
{
var context = new DatabaseEntities();
var Results =
from a in context.UserData
join b in context.UserDetails on a.Index equals b.Index into c
select new UserData{ Index = a.Index, Name = a.Name, PersonalNo = a.PersonalNo,
Details= c.ToList<UserDetails>() };
return Results;
}
Is there anybody who can help me out. In case more infos needed, please ask.
Thanks.
The following example is working. To get it working you can use object. See below the example:
public class UserData
{
public int Index{ get; set; }
public string Name{ get; set; }
public string PersonalNo { get; set; }
public List<object> Details { get; set; }
}
public class UserDetails
{
public int Age;
public string profession;
public string gender;
}
public IEnumerable<Userdata> GetUserData()
{
var context = new DatabaseEntities();
var Results =
from a in context.UserData
join b in context.UserDetails on a.Index equals b.Index into c
select new UserData{ Index = a.Index, Name = a.Name, PersonalNo = a.PersonalNo,
Details= c.ToList<object>() };
return Results;
}
The Type in the Watch windows is names as "object {MyTestApp.UserDetails}"
So basically it is working as I did it. But I need to cast it appropriate. Possibly now it is easier to help me.
Any suggestions?
I'm new to MVC and EF and LINQ.
I used EF and DB first to create all the models from the DB. I also created a ViewModel "CourseDetailsVM":
public class CourseDetailsVM
{
public int CourseId { get; set; }
public int CategoryFk { get; set; }
public int SoftwareFk { get; set; }
public int TeacherFk { get; set; }
public string CourseCode { get; set; }
public string CourseCodeMs { get; set; }
public string CourseName { get; set; }
public string CourseDescriptionShort { get; set; }
public int CourseEventId { get; set; }
public int? CourseEventDurationInDays { get; set; }
public int? CourseEventPrice { get; set; }
public int CourseEventDateId { get; set; }
public DateTime? CourseEventDateTimeFrom { get; set; }
public DateTime? CourseEventDateTimeTo { get; set; }
}
In my Course Controller I try to get the Model from the Viewmodel using the following query (which works in linqpad but not in mvc) and I also use ViewData to access the repository (this works fine):
// GET: /Course/Details/5
public ActionResult Details(int id)
{
// get courses to display course details using ViewData
ViewData["Courses"] = _repository.GetCourses(id);
// get course events
var result = (from c in db.Courses
join ce in db.CourseEvents
on c.CourseId equals ce.CourseFk
join ced in db.CourseEventDates
on ce.CourseEventId equals ced.CourseEventFk
group ce by new { ce.CourseEventId, c.CourseId, c.CourseCode, c.CourseName, ce.CourseEventPrice } into grp
select new CourseDetailsVM
{
CourseEventId = grp.Key.CourseEventId,
CourseId = grp.Key.CourseId,
CourseCode = grp.Key.CourseCode,
CourseEventDateTimeFrom = (from c2 in db.CourseEventDates where (c2.CourseEventFk.Equals(grp.Key.CourseEventId)) select c2.CourseEventDateTimeFrom).Min(),
CourseEventDateTimeTo = (from c2 in db.CourseEventDates where (c2.CourseEventFk.Equals(grp.Key.CourseEventId)) select c2.CourseEventDateTimeFrom).Max(),
CourseEventDurationInDays = (from c2 in db.CourseEventDates where (c2.CourseEventFk.Equals(grp.Key.CourseEventId)) select c2.CourseEventDateTimeFrom).Count() / 2,
CourseName = grp.Key.CourseName,
CourseEventPrice = grp.Key.CourseEventPrice,
CourseEventDateId = grp.Key.CourseEventId
}).OrderBy(c => c.CourseEventDateTimeFrom);
return View("Details", result);
}
Since Linq compiles on runtime, I can compile the project without any errors. But when accessing the Course/Details view I get the following error:
Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
The error occurs when making an new instance of CourseDetailsVM on the following fields: CourseEventDateTimeFrom, CourseEventDateTimeTo, CourseEventDurationInDays
I tried fill the mentioned properties using hard coded values and it worked fine. So I know, where the error occurs, but I don't know why and how to solve it.
As requested by Yuliam Chandra, the content of the CourseEventDate class (generated by EF):
public partial class CourseEventDate
{
public int CourseEventDateId { get; set; }
public Nullable<int> CourseEventFk { get; set; }
public Nullable<System.DateTime> CourseEventDateTimeFrom { get; set; }
public Nullable<System.DateTime> CourseEventDateTimeTo { get; set; }
public virtual CourseEvent CourseEvent { get; set; }
}
I hope that sb of you guys can help me.
Thank you,
Ronin
The error could be caused when comparing CourseEventFk (int?) and CourseEventId (int) using Equals where its parameter accepts object type which is a CLR method. LINQ to Entities doesn't support CLR method.
Try to use == operator, which somewhat compatible to L2S, on following code.
CourseEventDateTimeFrom = ..where (c2.CourseEventFk == grp.Key.CourseEventId)..
CourseEventDateTimeTo = ..where (c2.CourseEventFk == grp.Key.CourseEventId)..
CourseEventDurationInDays = ..where (c2.CourseEventFk == grp.Key.CourseEventId)..
What I did in the past when I have encountered this kind of error was to create a static object (or anything that I needed at the given time) and did conversion myself such as following:
Private static double? myDoubleConversion(string sInput)
{
//conversion logic comes here
return result;
}
I'm starting to use Entity Framework Code First.
Suppose to have such POCO's (ultimately simplified):
public class BortStructure
{
public Guid Id { get; set; }
public String Name { get; set; }
}
public class Slot
{
public Guid Id { get; set; }
public String Name { get; set; }
public BortStructure { get; set; }
}
public class SystemType
{
public Guid Id { get; set; }
public String Name {get; set; }
}
public class SlotSystemType
{
public Guid Id { get; set; }
public Slot Slot { get; set; }
public SystemType SystemType {get; set; }
}
and a context
public MyContext : DbContext
{
public DbSet<BortStructure> BortStructures { get; set; }
public DbSet<Slot> Slots{ get; set; }
public DbSet<SystemType> SystemTypes { get; set; }
public DbSet<SlotSystemType> SlotSystemTypes { get; set; }
}
I have a task to get BortStructure by Id with list of attached Slots, each one with list of systemTypes attached.
Using SQL allowed me to do that with some JOIN's:
SELECT BortStructures.Id, BortStructures.Name, Slots.Id,
Slots.Name, SystemType.Id, SystemType.Name FROM
((BortStructures LEFT JOIN Slots ON BortStructures.Id = Slots.BortStructureId)
LEFT JOIN SlotSystemTypes ON SlotSystemTypes.SlotId = Slots.Id)
LEFT JOIN SystemTypes ON SystemTypes.Id = SlotSystemTypes.SystemTypeId
WHERE BortStructures.Id='XXXXXX' ORDER BY Slots.Id, SystemType.Id
But with Entity Framework Code First I don't have any idea howto do that.
If I use
var slotSystemTypes = from sl in MyContext.SlotSystemTypes
where sl.Slot.BortStructure.Id = XXXXXX
orderby sl.Slot.Id, sl.SystemType.Id
select sl;
i, of course, will receive nothing if BortStructure consists of no Slots/Slots without any SystemTypes attached.
Instead of getting BortStructure with empty list of Slots/with Slots, each one with empty list of SystemTypes attached as I expect to get.
Is there any way to archive that with single LINQ query for my database configuration?
You can use join operator example:
string[] categories = new string[]{
"Beverages",
"Condiments",
"Vegetables",
"Dairy Products",
"Seafood" };
List<Product> products = GetProductList();
var q =
from c in categories
join p in products on c equals p.Category
select new { Category = c, p.ProductName };
foreach (var v in q)
{
Console.WriteLine(v.ProductName + ": " + v.Category);
}
more samples in: http://code.msdn.microsoft.com/LINQ-Join-Operators-dabef4e9