linq to entities throwing some error - c#

hi i am using this controller
public ActionResult gridview()
{
var jsonData = new {
total = 1, //todo: calculate
page = 1,
records = db.TestModels.Count(),
rows = (
from question in db.TestModels
select new {
id = question.Dataid,
cell = new string[] {
question.Dataid, question.Name, question.Emailid
}
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
}
am getting this error
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
can any body help

You are trying to use new string[] in a SQL query, but that cannot be translated to SQL. You need to get the data you need from the model, and perform the conversion in-memory. Use .AsEnumerable() to indicate you want to do the following in-memory, and not in the SQL statement.
Something like this:
var jsonData = new {
total = 1, //todo: calculate
page = 1,
records = db.TestModels.Count(),
rows = db.TestModels
.Select(x => new { x.Dataid, x.Name, x.Emailid })
.AsEnumerable()
.Select(x => new {
id = x.DataId,
cell = new string[3] { x.Dataid, x.Name, x.Emailid }
})
.ToArray();
};

Related

how can I reduce 2 select to 1 select linq to gain performance?

my question is simple but I got stuck with something. Can you tell me how can I reduce 2 select into 1 select LINQ in c#? I am using CloudNative.CloudEvents NuGet package for cloud-native events.
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent())
.Select(_ =>
new CloudEvent()
{
Type = _.EventType,
Subject = _.Subject,
Source = _.Source,
Data = _
});
input is a parameter from cosmosDbTrigger it`s type : IReadOnlyList
OrderDocument.cs
public class OrderDocument
{
public string Id { get; private set; }
public string Json { get; private set; }
public OrderDocument(string id, string json)
{
Id = id;
Json = json;
}
public OrderEvent ToOrderEvent() => OrderEventHelper.ToOrderEvent(Json);
}
OrderEventHelper.cs
public static OrderEvent ToOrderEvent(string json)
{
ArgumentHelper.ThrowIfNullOrEmpty(json);
var orderEvent = JsonConvert.DeserializeObject<OrderEvent>(json);
var eventDefinition = OrderEvents.EventDefinitions.SingleOrDefault(_ => _.EventType == orderEvent.EventType);
return eventDefinition == null
? orderEvent
: new OrderEvent(
orderEvent.Id,
orderEvent.Source,
orderEvent.EventType,
orderEvent.Subject,
orderEvent.DataContentType,
orderEvent.DataSchema,
orderEvent.Timestamp,
JsonConvert.DeserializeObject(orderEvent.Payload.ToString(), eventDefinition.PayloadType),
orderEvent.TraceId);
}
linq extensions are basically for loops in the background. If you want to perform multiple actions against a list, perhaps making your own simple for loop where you can manage that yourself would work.
Your code:
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent())
.Select(_ =>
new CloudEvent()
{
Type = _.EventType,
Subject = _.Subject,
Source = _.Source,
Data = _
});
could be changed to:
// our result set, rather than the one returned from linq Select
var results = new List<CloudEvent>();
foreach(var x in input){
// create the order event here
var temporaryOrderEvent = new OrderDocument(x.Id, x.ToString()).ToOrderEvent();
// add the Cloud event to our result set
results.Add(new CloudEvent()
{
Type = temporaryOrderEvent .EventType,
Subject = temporaryOrderEvent .Subject,
Source = temporaryOrderEvent .Source,
Data = temporaryOrderEvent
});
}
where you then have a result list to work with.
If you wanted to keep it all in linq, you could instead perform all of your logic in the first Select, and ensure that it returns a CloudEvent. Notice here that you can employ the use of curly brackets in the linq statement to evaluate a function rather than a single variable value:
var orderEvents = input
.Select(x =>
{
// create the order event here
var temporaryOrderEvent = new OrderDocument(x.Id, x.ToString()).ToOrderEvent();
// return the Cloud event here
return new CloudEvent()
{
Type = temporaryOrderEvent .EventType,
Subject = temporaryOrderEvent .Subject,
Source = temporaryOrderEvent .Source,
Data = temporaryOrderEvent
};
});
How about putting conversion to OrderEvent and using ToCloudEvent in the same Select?
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent().ToCloudEvent())
public class OrderEvent
{
public CloudEvent ToCloudEvent()
{
new CloudEvent()
{
Type = this.EventType,
Subject = this.Subject,
Source = this.Source,
Data = this
};
}
}

LINQ to Objects - Reduce repetition - Map inside select statement

I am using LINQ to objects to run the multiple queries like below, I want to retain a separate method for each of the queries below but I want to have a function to map inside the select statement.
GetDTOCourseListActiveCourses
GetDTOCourseListWithValidDates
GetDTOCourseListRequirePayments
With each I am currently doing a manual mapping exercise inside the select for each query like below:
public IList<DTOCourse> GetDTOCourseListActiveCourses()
{
var query = _UoW.tblcoursRepo.All.Where(c => c.IsActive == true);
IList<DTOCourse> courselist = new List<DTOCourse>();
courselist = query.Select(x => new DTOCourse
{
////// BUT, I want to create a function here to do the mapping //
courseId = x.CourseID,
courseTitle = x.CourseTitle,
mainHeading = x.MainHeading.description,
courseType = x.ListType.description,
courseStatus = x.ListStatus.description,
orgId = x.OrgID.Value
}).ToList();
return courselist;
}
I have created the following method to map to the DTO class, this works fine when converting a single instance:
public DTOCourse MaptblcourseToDTOCourse(tblcours course)
{
DTOCourse dto = new DTOCourse
{
courseId = course.CourseID,
courseTitle = course.CourseTitle,
mainHeading = course.MainHeading.description,
courseType = course.ListType.description,
courseStatus = course.ListStatus.description,
orgId = course.OrgID.Value
};
return dto;
}
How can I combine this method to map within a select? I'm looking for something like below:
public IList<DTOCourse> GetDTOCourseListActiveCourses()
{
var query = _UoW.tblcoursRepo.All.Where(c => c.IsActive == true);
IList<DTOCourse> courselist = new List<DTOCourse>();
courselist = query.Select(x => new DTOCourse
{
MaptblcoursToDTOCourse(x)
}).ToList();
return courselist;
}
You are almost there. You can call your mapping method in your Select call like this:
courselist = query.Select(x => MaptblcoursToDTOCourse(x)).ToList();
Or even shorter:
courselist = query.Select(MaptblcoursToDTOCourse).ToList();

Problem returning entity grouped with LINQ in HTTP GET

What I'm doing wrong in this method below? I created a group with linq because I need to group the list by 2 columns and for this grouping I will have a list of files.
[HttpGet]
[Route("versions-by-period")]
public IActionResult GetVersionsByPeriodId(int entityId, int periodId)
{
var versionsInvoiceBillet = db.RemittanceInvoiceBilletVersionsCompacts
.Where(x => x.LegalEntityId == entityId && x.PeriodId == periodId && x.IsCurrent && x.DownloadHash != null)
.GroupBy(x => new { x.LifePolicyNumber, x.LegalEntityGroupNumber },
i => new { i.DownloadHash, i.FileTypeEnum, i.DueDate }, (key, group) => new
{
LifePolicyNumber = key.LifePolicyNumber,
LegalEntityGroupNumber = key.LegalEntityGroupNumber,
Files = group.ToList()
});
return Ok(versionsInvoiceBillet.Select(x => new {
lifePolicyNumber = x.LifePolicyNumber,
legalEntityGroupNumber = x.LegalEntityGroupNumber,
invoiceAndBillet = x.Files.Select(f => new {
downloadHash = f.DownloadHash,
fileTypeEnum = f.FileTypeEnum,
dueDatet = f.DueDate
})
}));
}
If I try to call this method with Postman, the body comes empty. The problem is in invoiceAndBillet information that is returned, if I change to below, the body comes filled.
return Ok(versionsInvoiceBillet.Select(x => new {
lifePolicyNumber = x.LifePolicyNumber,
legalEntityGroupNumber = x.LegalEntityGroupNumber,
invoiceAndBillet = x.Files.Select
}));
If I try to debug the selection that I'm trying to return, I get this message below:

how to use an Anonymous Type

I have this code:
List<MyObjectOne> myListOne = new List<MyObjectOne>(){new MyObjectOne { ID = 1, field2 = 2}};
List<MyObjectTwo> myListTwo = new List<MyObjectTwo>(){new MyObjectTwo { ID = 4, field6 = "string"}};
bool hasSomething = false;
var result = new[] { new {ID = 0 }}.ToList();
if (hasSomething)
{
// Use list one.
result = myListOne.Select(x => new { ID = x.ID});
}
else
{
// Use list two.
result = myListTwo.Select(x => new { ID = x.ID });
}
foreach (var item in result)
{
// Some logic to manipulate item.ID.
item.ID;
}
What I trying to do it's to use the same anonymous type to select a list of IDs from two different lists. So I use the Select(x => new { ID = x.ID }) in order to create the anonymous type for each table in order to have only one for loop.
The error raised is "Cannot implicitly convert type IEnumerable to List"
¿any idea?
Assuming ID in MyObjectOne and MyObjectTwo are both int's, your code will work if you replace ToList with AsEnumerable:
var result = new[] { new { ID = 0 } }.AsEnumerable();
If the ID properties are some other type (e.g. long's), you need to specify that when creating the anonymous type here:
var result = new[] { new { ID = 0L } }.AsEnumerable();
Or like this:
var result = new[] { new { ID = (long)0 } }.AsEnumerable();
However, this kind of code is kind of confusing, and I wouldn't recommend it for a production environment. Here's an alternative solution that avoids creating a 'dummy' object just for implicit anonymous typing:
var result = hasSomething
? myListOne.Select(x => new { ID = x.ID })
: myListTwo.Select(x => new { ID = x.ID });

Concat strings in a projection (Linq)

How can I concat two string in a projection?
This is what I have so far:
IEnumerable<NameIdentity> data = null;
JsonResult res;
using (DBContext _db = new DBContext())
{
data = MyEntity.GetEntities(_db).OrderBy(a=> a.name)
.Select(b=> new NameIdentity
{
ID = b.entityID,
Name = String.Join(" - ", new String[]{ b.year, b.name })
});
res = Json(data.ToList(), JsonRequestBehavior.AllowGet);
}
I need to concatenate the year and name properties in the Name propety of my projection.
The error that is giving me is an "NotSupportedException" that says that the LINQ to Entities doesn't recognize de Join() method and it cannot be translated to a store expression.
data = MyEntity.GetEntities(_db).OrderBy(a=> a.name)
.Select(b=> new NameIdentity
{
ID = b.entityID,
Name = b.year +"-" + b.name
});
While you are using linq-to-entities you cannot use arbitrary .NET methods in query, You can use EdmFunctions, Here I have use EdmFunctions.Concat
data = MyEntity.GetEntities(_db).OrderBy(a=> a.name)
.Select(b=> new NameIdentity
{
ID = b.entityID,
Name = EdmFunctions.Concat(b.year, "-", b.name)
});
You can also use Canonical functions

Categories

Resources