Integrating custom method into LINQ to Entities query - asp.net-mvc-3

I have a custom method that performs some calculation on a set of data:
private int GetPercentages(int OriginalValue, int TotalValue)
{
var newValue = (int)Math.Round(((decimal)OriginalValue / (decimal)TotalValue) * 100);
return newValue;
}
I need to be able to run this method inside of a LINQ to Entities query:
var data = from SurveyResponseModel in db.SurveyResponseModels
group SurveyResponseModel by SurveyResponseModel.MemberId into resultCount
select new ResultsViewModel()
{
MemberId = resultCount.Key,
PatientFollowUpResult = db.SurveyResponseModels.Count(r => r.PatientFollowUp),
PatientFollowUpResultPct = GetPercentages(db.SurveyResponseModels.Count(r => r.PatientFollowUp),totalResponsesResult),
ChangeCodingPracticeResult = db.SurveyResponseModels.Count(r => r.ChangeCodingPractice),
};
I need to run this on about 20 more lines inside of the query so just sticking it inline doesn't seem like a great option. I understand that it needs to be converted into SQL syntax, but is there anything else like this that I can do?

You need to make a lambda expression that calculates the percentage like this:
Expression<Func<int, int, int>> calcPercentage =
(OriginalValue, TotalValue) => (int)Math.Round(((decimal)OriginalValue / (decimal)TotalValue) * 100);
And use it like this:
var data = from SurveyResponseModel in db.SurveyResponseModels.ToExpandable()
group SurveyResponseModel by SurveyResponseModel.MemberId into resultCount
select new ResultsViewModel()
{
MemberId = resultCount.Key,
PatientFollowUpResult = db.SurveyResponseModels.Count(r => r.PatientFollowUp),
PatientFollowUpResultPct = calcPercentage.Invoke(db.SurveyResponseModels.Count(r => r.PatientFollowUp), totalResponsesResult),
ChangeCodingPracticeResult = db.SurveyResponseModels.Count(r => r.ChangeCodingPractice),
};
More info about calling functions in LINQ queries here.

Related

IQueryable.Union/Concat in .net core 3

I want to add a dummy member to an IQueryable and came up with this solution:
IQueryable<Geography> geographies = _unitOfWork.GeographyRepository.GetAll(); //DbSet<Geography>
var dummyGeographies = new Geography[] { new Geography { Id = -1, Name = "All" } }.AsQueryable();
var combinedGeographies = geographies.Union(dummyGeographies);
var test = combinedGeographies.ToList(); //throws runtime exc
But it throws the following exception:
Processing of the LINQ expression 'DbSet
.Union(EnumerableQuery { Geography, })' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core.
How could I make it work?!
you can only union on data structure which are the same
IQueryable is only applicable if the query expression not been been expressed (ToList) before its run against db and you want the expression modifiable . aka nothing which which is not going to db as a query needs to be IQueryable (simple explanation better to research and understand this yourself)
List<Geography> geographies = _unitOfWork.GeographyRepository
.GetAll() //DbSet<Geography>
.Select(o => new Geography { Id = o.Id, Name = o.Name })
.ToList();
List<Geography> dummyGeographies = new List<Geography>() {
new Geography[] { new Geography { Id = -1, Name = "All" } }
};
var combinedGeographies = geographies.Union(dummyGeographies);
var test = combinedGeographies.ToList();
I was able to achieve it with the following code:
IQueryable<Geography> geographies = _unitOfWork.GeographyRepository.GetAll().Select(o => new Geography { Id = o.Id, Name = o.Name });
IQueryable<Geography> dummyGeographies = _unitOfWork.GeographyRepository.GetAll().Select(o => new Geography { Id = -1, Name = "All" });
var combinedGeographies = geographies.Union(dummyGeographies);

dynamic linq queries in linq-to-entities

what I want is to include 3 tables in my query and select only the last table fields.
[WebMethod]
public Project[] GetAlll(int passeid)//passed id is the id of fieldteammeber table I am passing
{
var arr = db.Project.Include("FieldTeamMember")
.Include("FieldTeam")
.Where(ft_id=ftm_id and ft_mid=prj_ftm_id and FTM_ID=passeid)
.ToArray();
return arr;
}
want to select the project table fields. there are F keys between tables in the model.
I think this is the query you're looking for based on your description:
int memberId = 1;
var projects = db.Projects
.Where(p => p.FieldTeam
.FieldTeamMembers.Any(ftm => ftm.Id == memberId));
Alternatively, if this is more readable to you:
int fieldTeamMemberId = 1;
var projects = db.FieldTeamMembers.Where(ftm => ftm.Id == memberId)
.Select(ftm => ftm.FieldTeam.Project)
.Distinct();

Select top N with record from DataTable with some sorting using Linq

I have created a DataTable. I have populated the rows of the DataTable after some operations.
I am very new to Linq I want to Get the Top "N" Records from the DataTable implementing also some paging.
Let dataTable is the DataTable having some data.
I am need something like this
var Query = from d in dataTable
Order by columnName
skip( some records pageSize * pageNumber)
Select top N from dataTable
The column Name, Page size ,pageNumber and the N will passed as arguments
Try this:
var query = dataTable.AsEnumerable()
.OrderBy(c => c.columnName)
.Select(r => new {...})
.Skip(10)
.Take(5)
Try this,
int numberOfObjectsPerPage = 20;
var queryResultPage = dataTable.OrderBy(c => c.columnName).Select(r => r).Skip(numberOfObjectsPerPage * pageNumber).Take(numberOfObjectsPerPage);
Try this
var Query = dataTable.Select(o=>o).OrderBy(o=>o.columnName).Skip(pageSize * pageNumber).Take(N);
EDIT
For pass column name you should to add this code
public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
{
var param = Expression.Parameter(typeof(T), "p");
var prop = Expression.Property(param, SortField);
var exp = Expression.Lambda(prop, param);
string method = Ascending ? "OrderBy" : "OrderByDescending";
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
return q.Provider.CreateQuery<T>(mce);
}
And then you could call it in this way
var values = dataTable.OrderByField("columnName");

EF Code First selecting rows based on many to many relationship

I have the following code in my repository:
public PagedResult<Post> GetAllPublishedByTag(int tagId, int start, int max)
{
var query = Database.Set<Post>().Where(p => p.IsPublished)
.OrderByDescending(p => p.CreatedAt)
.Skip(start)
.Take(max);
int total = query.Count();
var result = query.ToList();
return new PagedResult<Post>(result, total);
}
This will give me all published posts. But what I want is selecting all published posts for a certain tag. My model is setup in such a way that tags have a many to many relationship to posts. I tried to slightly modify the above code but this did not work:
public PagedResult<Post> GetAllPublishedByTag(Tag tag, int start, int max)
{
var query = Database.Set<Post>().Where(p => p.Tags.Contains(tag) && p.IsPublished)
.OrderByDescending(p => p.CreatedAt)
.Skip(start)
.Take(max);
int total = query.Count();
var result = query.ToList();
return new PagedResult<Post>(result, total);
}
I would prefer to pass in the tagId (as per the first code example) as opposed to the tag object but not sure how to correctly write the LINQ statement.
var query = Database.Set<Post>().Where(p => p.Tags.Any(t => t.Id == tagId) && p.IsPublished)
.OrderByDescending(p => p.CreatedAt)
.Skip(start)
.Take(max);
Side Note: I believe you may have issues with your pagination, as the variable total is calculated after skip/take are called.

Linq to SQL construct a custom object externally - join from another object

Continued from this solution (thanks Daniel Hilgarth)
return db.Tags.Select(ConstructTagItem());
And the method:
private Expression<Func<Tag, TagItem>> ConstructTagItem()
{
return a => new TagItem {ID = a.Id Name = a.Name };
}
Additional question, how do i use it in this scenario then:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = new TagItem
{
ID = c.Tag.Id,
Name = c.Tag.Name
}
});
I want to reuse the method from the other answer:
private Expression<Func<Tag, TagItem>> ConstructTagItem
{
get { return a => new TagItem {ID = a.Id Name = a.Name }; }
}
To construct something like this:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = ConstructTagItem // TODO: need some way to tell the method that it should use c.Tag
});
I want to use the same construction of my TagItem multiple places. This will make it easier if the object changes, and save lines.
I guess that I somehow have to define that it is c.Tag into ConstructTagItem(), but I really don't know much about expressions yet. So i hope that someone is able to help?
I'm not sure if I have a full handle on what you're trying to do. What does "use it in this scenario" mean? Can you mimic your previous technique with something like this in order to encapsulate creating a NewsTagItem, or is it something else you're trying to achieve?
private Expression<Func<News_Attribute, NewsTagItem>> ConstructNewsTagItem()
{
return c => new NewsTagItem
{
NewsID = c.News_Id,
Name = a.Name
TagID = c.Tag_Id,
Content = c.Content,
Attribute = new TagItem
{
ID = c.Tag.Id,
Name = c.Tag.Name
}
}
});
db.News_Attributes.Select(ConstructNewsTagItem());
UPDATE:
OK, we can't directly re-use your ConstructTagItem() because it returns an expression containing a function. What you need is a MemberInitExpression. It's a little tricky to create by hand, but we can use a trick whereby we create the expression we desire wrapped with a thunk, so that it isn't evaluated, and then grab the body of the thunk to get the expression. See the snippet below:
private Expression GenerateNewTagItem(TagItem c)
{
Expression<Func<TagItem>> expr = () => new TagItem { ID = c.ID, Name = c.Name };
return expr.Body;
}
With this function, we can now do pretty much exactly what you want:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = GenerateNewTagItem(c)
});
Pretty neat right?

Resources