No supported translation to SQL - linq-to-sql

Given this in my datacontext:
public class EventsForUserID
{
public string eventName { get; set; }
public int eventID { get; set; }
public string eventIdentifier { get; set; }
public DateTime eventOpenDate { get; set; }
public DateTime eventCloseDate { get; set; }
public bool eventDisabled { get; set; }
public EventsForUserID() {}
public EventsForUserID(string pEventName, int pEventID, string pEventIdentifier, DateTime pEventOpenDate, DateTime pEventCloseDate, bool pEventDisabled)
{
this.eventName = pEventName;
this.eventID = pEventID;
this.eventIdentifier = pEventIdentifier;
this.eventOpenDate = pEventOpenDate;
this.eventCloseDate = pEventCloseDate;
this.eventDisabled = pEventDisabled;
}
}
public List<EventsForUserID> GetEventsForUserID(string userID, bool excludeDisabled)
{
var e =
from ex in this.Exhibitors
join ev in this.Events on ex.EventID equals ev.EventID
where ex.UserID.ToString() == userID
select new EventsForUserID (
ev.EventName,
ev.EventID,
ev.EventID + "[::]" + ex.ExhibitorID + "[::]" + ex.AccountDisabled + "[::]" + ev.EventDisabled,
ev.OpenDate.Value,
ev.CloseDate.Value,
ev.EventDisabled
);
if (excludeDisabled) {
e = from ev in e
where ev.eventDisabled != true
select ev;
}
return e.ToList();
}
I get the error:
The member 'LeadsDataContext+EventsForUserID.eventDisabled' has no supported translation to SQL.
on the return.ToList() line.
I've tried all sorts....AsQueryable() etc
I figure it because EventsForUserID is not a true sql table, but then I thought LINQ was for performing queries over many type of object.
Am I missing a cast of some sort.
Many thanks, N

Unfortunately you cannot mix linq-to-objects and linq-to-sql freely in the same query. If you are running the query as a linq-to-sql query, everything must be translated to sql.
Try to split your code into two queries. The first one should retrieve the relevant data from the database using linq-to-sql. The second uses linq-to-objects to do the final filtering/manipulation of data.

Related

Populating an object from an SQL Query

I want to populate my Master Detail object with data from an SQL Server query.
However I don't seem to form the Detail part of the query correctly.
Is it even possible?
I have the following classes
public class OrderCountReportHeader : IMyReport
{
[Key]
public int Id { get; set; }
public DateTime RunAt { get; set; }
public string Name { get; set; }
public virtual List<OrderCountReportDetail> Details { get; set; }
}
public class OrderCountReportDetail {
public virtual OrderBankReportHeader Header { get; set; }
public string ProductCode { get; set; }
public int Quantity { get; set; }
}
and I want to populate an instance of OrderCountReportHeader from the output of an SQL Query
private static string ReportSql() {
return #"
SET NOCOUNT ON;
select 1 as Id, getdate() as RunAt, 'test' as Name;
select 'RC' as ProductCode , 5 as Quantity; "
;
}
var result = context.Database.SqlQuery<OrderCountReportHeader>(sql).ToArray()[0];
Assert.AreEqual(#"test", s.Name); // true
Assert.AreEqual("RC", s.Details[0].ProductCode); // fails because Details is null
I wound up using two separate calls to SqlQuery
though I would be pleased to know a better way.
var header = connect.Database.SqlQuery<OrderCountReportHeader>(ReportSqlHeader()).ToArray()[0];
var details = connect.Database.SqlQuery<OrderCountReportDetail>(ReportSqlDetails()).ToList();
foreach (var det in details)
{
det.Header = header;
}
header.Details = details;

How to retrieve the attribute of related object in linq, select projection

I am trying to retrieve the Person name in my viewmodel while projection in the below code:
// GET api/Tickets
public IQueryable Get()
{
var model = Uow.Tickets.GetAll().OrderByDescending(m => m.DateTimeTag)
.Select(m => new TicketViewModel
{
Id = m.Id,
TicketTitle = m.TicketTitle,
TicketBody = m.TicketBody,
DateTimeTag = m.DateTimeTag,
//AssignedTo = Uow.Persons.GetById(m.AssignedToPersonId).Name,
Status = m.Status.ToString(),
NoOfReplys = m.Replys.Count()
});
return model;
}
But when I uncomment the AssignedTo line, it gives me the error:
InnerException: {
Message: "An error has occurred.",
ExceptionMessage: "LINQ to Entities does not recognize the method 'Ticketing.Model.Person GetById(Int32)' method, and this method cannot be translated into a store expression.",
ExceptionType: "System.NotSupportedException",
StackTrace: " at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTranslator.Translate(ExpressionConverter parent, MethodCallExpression call) at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq) at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) blah blah blah
The TicketViewModel class is:
public class TicketViewModel
{
public int Id { get; set; }
public string TicketTitle { get; set; }
public string TicketBody { get; set; }
public DateTime DateTimeTag { get; set; }
public string AssignedTo { get; set; }
public string Status { get; set; }
public int NoOfReplys { get; set; }
}
The actual Ticket class is:
public class Ticket
{
public int Id { get; set; }
public string TicketTitle { get; set; }
public string TicketBody { get; set; }
public DateTime DateTimeTag { get; set; }
public int AssignedToPersonId { get; set; }
public Status Status { get; set; }
public virtual ICollection<Reply> Replys { get; set; }
}
My desired output is:
[
{
Id: 3,
TicketTitle: "a problem",
TicketBody: "problem descripted here.",
DateTimeTag: "2012-04-21T00:00:00",
AssignedTo: "Peter", <== ATTENTION!!!
Status: "Open",
NoOfReplys: 0
}
]
Here, Peter is the name of the person who its id is in the ticket object.
My goal is to show the name instead of personId.
may be there is a better way, please help me do that.
thanks
In this case I think that your property:
public int AssignedToPersonId { get; set; }
should be:
public Person AssignedToPerson { get; set; }
in your Ticket class. Mapping to the reference is generally better so that you can access properties like this using Linq. This way the line that is giving you trouble can be:
AssignedTo = AssignedToPerson.Name
The reason it isn't working right now is because Entity Framework has no idea how to convert your line:
Uow.Persons.GetById(m.AssignedToPersonId).Name
to a Query expression. By using a reference mentioned above you will instead create a Join between the two tables and get back the desired data in a single query.
The other and probably less attractive option is to store the Id in your View Model and then do a query for the name outside your Linq query. This will work because you have already retrieve items from the database. Untested example below:
public IQueryable Get()
{
var model = Uow.Tickets.GetAll().OrderByDescending(m => m.DateTimeTag)
.Select(m => new TicketViewModel
{
Id = m.Id,
TicketTitle = m.TicketTitle,
TicketBody = m.TicketBody,
DateTimeTag = m.DateTimeTag,
AssignedToPersonId = m.AssignedToPersonId,
Status = m.Status.ToString(),
NoOfReplys = m.Replys.Count()
}).ToList();
model.ForEach(m => m.AssignedTo = Uow.Persons.GetById(m.AssignedToPersonId).Name);
return model;
}
Note however that this second method is making an additional query to the database for each Ticket object returned in the first query.

LINQ to SQL Insert (one to many relationship using custom entity classes and [Association] attribute)

I am currently delving into LINQ to SQL as it looks cool, and potentially much more useful than ADO.NET in many circumstances.
I have used LINQ to SQL before, but I created all the domain classes using the LINQ to SQL Class designer, and I don't really want to use it as I would rather know what is going on 'behind the scenes' rather than putting it down .NET magic. Hence, I have been attempting to create my domain (or entity) classes manually using LINQ attributes.
I was finding it all ok untill I ran into problems whilst trying to model a one to many relationship in my DB. There is a table Meets that has a column LeaderId, which is a foreign key to the table Members
This is how I have the entity classes set up:
Meet.cs
[Table(Name = "dbo.Meets")]
public class Meet
{
private EntityRef<Member> _leader;
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int MeetId { get; set; }
[Column]
public string Location { get; set; }
[Column]
public DateTime Date { get; set; }
[Association(Name = "FK_Meets_Members", Storage = "_leader")]
public Member Leader
{
get { return _leader.Entity; }
set { _leader.Entity = value; }
}
}
Member.cs
[Table(Name = "dbo.Members")]
public class Member
{
private EntitySet<Meet> _meets;
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int MemberId { get; set; }
[Column]
public string Name { get; set; }
[Column]
public string Hometown { get; set; }
[Column]
public string Info { get; set; }
[Column]
public ComitteeRole ComitteeRole { get; set; }
[Association(Name = "FK_Meets_Members", Storage = "_meets")]
public ICollection<Meet> Meets
{
get { return _meets; }
set { _meets.Assign(value); }
}
}
Selects work on the Meets table and likewise on the Members table and associated entities are loaded fine. However when I try and do an insert into the Meets table I am getting the good old 'Object reference not set to an instance of an object' error.
Now the problem must lie with what I am using to store the the LeaderId when I am adding a new Meet entity. I am setting the foreign key in my object like so:
Meet meet = new Meet();
meet.Leader.MemberId = 1;
However, when I am doing the LINQ insert it doesn't seem to understand that the MemberId of the Leader property is the value to put in the foreign key column in the Meets table.
I realise this could probably be solved by adding a separate property to the Meet class like so:
[Column]
public int LeaderId { get; set; }
However, I don't want to clutter my class with an extra property that is a duplicate of the MemberId property of the Leader property.
Hope you understand me...
Can anyone help?
I figured this problem out, I did have to add the extra LeaderId property to represent the foreign key, then mark this as the foreign key in the Associate attribute named parameter 'ThisKey' like so:
Meet.cs
[Table(Name = "dbo.Meets")]
public class Meet
{
private EntityRef<Member> _leader;
public Meet()
{
_leader = default(EntityRef<Member>);
}
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int MeetId { get; set; }
[Column]
public string Location { get; set; }
[Column]
public DateTime Date { get; set; }
[Column]
public int LeaderId { get; set; }
[Association(Name = "Member_Meet", Storage = "_leader", ThisKey = "LeaderId", OtherKey = "MemberId", IsForeignKey = true)]
public Member Leader
{
get { return _leader.Entity; }
set { _leader.Entity = value; }
}
}

Linq strongly typed datacontext will not compile

I am trying to fetch all data from a SQL Server table using a strongly typed LINQ To SQL datacontext, as per this MSDN example: How to: Connect to a Database (LINQ to SQL)
My code is as follows:
public class bioAppointments
{
string _strConnString = "Data Source=local; Initial Catalog=MyDatabase; User Id=MyUser; Password=MyPassword;";
public List<Appointment> getAllAppointments()
{
SqlConnection connection = new SqlConnection(_strConnString);
Appt dc = new Appt(connection);
var query =
from appt in dc.myAppointments
select new Appointment
{
AppointmentId = appt.AppointmentId,
StartDate = appt.StartDate,
EndDate = appt.EndDate,
StartTime = appt.StartTime,
EndTime = appt.EndTime,
Notes = appt.Notes,
};
return query.ToList();
}
public partial class Appt : DataContext
{
public Table<Appointments> myAppointments;
public Appt(string connection) : base(connection) { }
}
public class Appointment
{
public int AppointmentId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public String Notes { get; set; }
}
}
I am getting a compile error:
The type or namespace name 'Appointments' could not be found (are you missing a using directive or an assembly reference?)
The squiggle is under in the Appt class.
Does anyone know what this is means and how I can fix it?
Instead of:
public Table<Appointments> myAppointments;
shouldn't it be this? (Singular)
public Table<Appointment> myAppointments;

Linq to SQL filtered association?

public class ForumTopic
{
public Guid ForumTopicId { get; set; }
public Guid OwnerId { get; set; }
public Guid CategoryId { get; set; }
public DateTime CreatedDate { get; set; }
public string Topic { get; set; }
public bool IsSticky { get; set; }
public bool IsClosed { get; set; }
public int ViewCount { get; set; }
public int TotalComments { get; set; }
public Comment LastComment { get; set; }
}
I then have a Linq query and I need to figure out how to populate the LastComment and I can't create a new ForumTopic becuase Linq tells me that is breaking the rules...
IQueryable<ForumTopic> query = from topic in context.ForumTopics
join comment in context.Comments on topic.ForumTopicId equals comment.TargetId into topicComments
from lastComment in topicComments.DefaultIfEmpty().OrderByDescending(c => c.CreatedDate).Take(1)
orderby topic.IsSticky, topic.CreatedDate descending
select topic;
The query returns everything correct in SQL, however topic.LastComment is null.
Any ideas?
The main problem is you're not assigning the LastComment. Without a relationship established in the database, it has no idea how to fill that object.
You're going to need to manually assign the comment:
IQueryable<ForumTopic> query = from topic in context.ForumTopics
orderby topic.IsSticky, topic.CreatedDate descending
select new ForumTopic
{
ForumTopicId = topic.ForumTopicId,
OwnerId = topic.OwnerId,
// .. etc
LastComment = topic.Comments.OrderByDescending(c => c.CreatedDate).FirstOrDefault();
};
Obviously, I'm assuming you have a parent-child relationship between topic and comments. If you don't, you should reconsider how you're using linq :p